diff --git a/ThunksList.md b/ThunksList.md index f94aba7..7c121ed 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -1,825 +1,829 @@ -# YY-Thunks Thunks 清单 - -此表展示了YY-Thunks(鸭船)可以解决的函数不存在问题,欢迎大家扩充! - -> 开头带`*`的函数并不建议使用,存在一些较大负面影响,仅用于编译通过处理,具体负面影响可参考注释内容。 - -## api-ms-win-core-handle-l1-1-0.dll -| 函数 | Fallback -| ---- | ----------- -| CompareObjectHandles | 不存在时,调用NtQueryObject以及DuplicateHandle。 - -## api-ms-win-core-path-l1-1-0.dll -| 函数 | Fallback -| ---- | ----------- -| PathIsUNCEx | 内部实现。 -| PathCchIsRoot | 内部实现。 -| PathCchAddBackslashEx | 内部实现。 -| PathCchAddBackslash | 调用PathCchAddBackslashEx。 -| PathCchRemoveBackslashEx | 内部实现。 -| PathCchRemoveBackslash | 调用PathCchRemoveBackslashEx。 -| PathCchSkipRoot | 内部实现。 -| PathCchStripToRoot | 内部实现。 -| PathCchRemoveFileSpec | 内部实现。 -| PathCchFindExtension | 内部实现。 -| PathCchAddExtension | 调用PathCchFindExtension。 -| PathCchRenameExtension | 调用PathCchFindExtension。 -| PathCchRemoveExtension | 调用PathCchFindExtension。 -| PathCchCanonicalizeEx | 不存在时,内部实现。 -| PathCchCanonicalize | 调用PathCchCanonicalizeEx。 -| PathCchCombineEx | 内部实现。 -| PathCchCombine | 调用PathCchCombineEx。 -| PathCchAppendEx | 调用PathCchCombineEx。 -| PathCchAppend | 调用PathCchAppendEx。 -| PathCchStripPrefix | 内部实现。 -| 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-threadpool-l1-2-0.dll -| 函数 | Fallback -| ---- | ----------- -| CreateThreadpoolWork | 不存在时,内部实现。 -| CloseThreadpoolWork | 不存在时,内部实现。 -| TrySubmitThreadpoolCallback | 不存在时,调用QueueUserWorkItem。 -| SubmitThreadpoolWork | 不存在时,调用QueueUserWorkItem。 -| WaitForThreadpoolWorkCallbacks | 不存在时,内部实现。 -| CreateThreadpoolTimer | 不存在时,内部实现。 -| CloseThreadpoolTimer | 不存在时,调用DeleteTimerQueueTimer。 -| SetThreadpoolTimer | 不存在时,调用CreateTimerQueueTimer。 -| WaitForThreadpoolTimerCallbacks | 不存在时,调用WaitForSingleObject。 -| SetEventWhenCallbackReturns | 不存在时,内部实现。 -| ReleaseSemaphoreWhenCallbackReturns | 不存在时,内部实现。 -| ReleaseMutexWhenCallbackReturns | 不存在时,内部实现。 -| LeaveCriticalSectionWhenCallbackReturns | 不存在时,内部实现。 -| FreeLibraryWhenCallbackReturns | 不存在时,内部实现。 -| CreateThreadpoolWait | 不存在时,内部实现。 -| CloseThreadpoolWait | 不存在时,调用UnregisterWait。 -| SetThreadpoolWait | 不存在时,调用RegisterWaitForSingleObject。 -| WaitForThreadpoolWaitCallbacks | 不存在时,调用WaitForSingleObject。 -| CreateThreadpoolIo | 不存在时,调用BindIoCompletionCallback。 -| CloseThreadpoolIo | 不存在时,内部实现。 -| StartThreadpoolIo | 不存在时,内部实现。 -| CancelThreadpoolIo | 不存在时,内部实现。 -| WaitForThreadpoolIoCallbacks | 不存在时,调用WaitForSingleObject。 -| CreateThreadpool | 不存在时,内部实现。 -| CloseThreadpool | 不存在时,内部实现。 -| SetThreadpoolThreadMaximum | 不存在时,内部实现,自己控制最大并行数量。 -| SetThreadpoolThreadMinimum | 不存在时,忽略,并总是返回成功。 -| CallbackMayRunLong | 不存在时,自己估算系统剩余可用线程数。 - -## api-ms-win-core-winrt-l1-1-0.dll -| 函数 | Fallback -| ---- | ----------- -| RoInitialize | 不存在时,调用 CoInitializeEx。 -| RoUninitialize | 不存在时,调用 CoUninitialize。 -| RoActivateInstance | 不存在时,返回 E_NOTIMPL。 -| RoRegisterActivationFactories | 不存在时,返回 E_NOTIMPL。 -| RoRevokeActivationFactories | 不存在时,什么也不做。 -| RoGetActivationFactory | 不存在时,返回 CLASS_E_CLASSNOTAVAILABLE -| RoRegisterForApartmentShutdown | 不存在时,返回 E_NOTIMPL。 -| RoUnregisterForApartmentShutdown | 不存在时,返回 E_NOTIMPL。 -| RoGetApartmentIdentifier | 不存在时,返回 E_NOTIMPL。 - -## api-ms-win-core-winrt-error-l1-1-0.dll -| 函数 | Fallback -| ---- | ----------- -| RoOriginateError | 不存在时,返回 TRUE. -| RoOriginateErrorW | 不存在时,返回 TRUE. - -## api-ms-win-core-winrt-string-l1-1-0.dll -| 函数 | Fallback -| ---- | ----------- -| WindowsCreateString | 不存在时,内部实现。 -| WindowsCreateStringReference | 不存在时,内部实现。 -| WindowsDeleteString | 不存在时,内部实现。 -| WindowsDuplicateString | 不存在时,内部实现。 -| WindowsGetStringLen | 不存在时,内部实现。 -| WindowsGetStringRawBuffer | 不存在时,内部实现。 -| WindowsIsStringEmpty | 不存在时,内部实现。 -| WindowsStringHasEmbeddedNull | 不存在时,内部实现。 -| WindowsCompareStringOrdinal | 不存在时,内部实现。 - -## advapi32.dll -| 函数 | Fallback -| ---- | ----------- -| RegDeleteKeyExW(A) | 不存在时,调用RegDeleteKeyW(A)。 -| RegSetKeyValueW(A) | 调用RegCreateKeyExW(A)以及RegSetValueExW(A)。 -| RegDeleteKeyValueW(A) | 调用RegOpenKeyExW(A)以及RegDeleteValueW(A)。 -| RegDeleteTreeW(A) | 调用SHDeleteKeyW(A)。 -| RegGetValueW(A) | 不存在时,调用RegQueryValueExW(A)。 -| RegCopyTreeW(A) | 不存在时,调用SHCopyKeyW(A)。 -| EventSetInformation | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventActivityIdControl | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventRegister | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventUnregister | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EnumerateTraceGuidsEx | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventEnabled | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventWrite | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventWriteTransfer | 不存在时,返回ERROR_NOT_SUPPORTED。 -| EventWriteEx | 不存在时,调用EventWriteTransfer。 -| EventWriteString | 不存在时,返回ERROR_NOT_SUPPORTED。 -| GetDynamicTimeZoneInformationEffectiveYears| 不存在时,直接读取`Time Zones`注册表。 -| AddMandatoryAce | 不存在时,调用RtlCopySid。 -| GetTokenInformation | 返回假装的 TokenVirtualizationAllowed、TokenAppContainerSid等。 - -## bcrypt.dll -| 函数 | Fallback -| ---- | ----------- -| BCryptOpenAlgorithmProvider | 不存在时,调用CryptAcquireContextW。目前支持的算法有:RC2、RC4、AES、DES、3DES、3DES-112、MD2、MD4、MD5、SHA1、SHA256、SHA384、SHA512、RNG、FIPS186DSARNG、DUALECRNG。 -| BCryptCloseAlgorithmProvider | 不存在时,调用CryptReleaseContext。 -| BCryptGenRandom | 不存在时,调用RtlGenRandom。 -| BCryptGetProperty | 不存在时,调用CryptGetKeyParam。 -| BCryptSetProperty | 不存在时,调用CryptSetKeyParam。 -| BCryptCreateHash | 不存在时,调用CryptCreateHash。 -| BCryptDestroyHash | 不存在时,调用CryptDestroyHash。 -| BCryptHashData | 不存在时,调用CryptHashData。 -| BCryptFinishHash | 不存在时,调用CryptGetHashParam。 -| BCryptDeriveKeyPBKDF2 | 不存在时,调用BCryptHashData。 -| BCryptDeriveKeyCapi | 不存在时,调用BCryptHashData。 -| BCryptEncrypt | 不存在时,调用CryptEncrypt。 -| BCryptDecrypt | 不存在时,调用CryptDecrypt。 -| BCryptGenerateSymmetricKey | 不存在时,调用CryptImportKey。 -| BCryptDestroyKey | 不存在时,调用CryptDestroyKey。 -| BCryptExportKey | 不存在时,调用CryptExportKey。 -| BCryptImportKey | 不存在时,调用CryptImportKey。 - -## bcryptprimitives.dll -| 函数 | Fallback -| ---- | ----------- -| ProcessPrng | 不存在时调用,RtlGenRandom。 - -## bluetoothapis.dll -| 函数 | Fallback -| ---- | ----------- -| BluetoothGATTGetCharacteristicValue | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTGetCharacteristics | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTGetDescriptors | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTGetServices | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTRegisterEvent | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTSetCharacteristicValue | 不存在时,返回ERROR_NOT_SUPPORTED。 -| BluetoothGATTSetDescriptorValue | 不存在时,返回ERROR_NOT_SUPPORTED。 - -## CfgMgr32.dll -| 函数 | Fallback -| ---- | ----------- -| CM_Get_DevNode_Property_ExW | 不存在时,调用CM_Get_DevNode_Registry_PropertyW。 -| CM_Set_DevNode_Property_ExW | 不存在时,调用CM_Set_DevNode_Registry_PropertyW。 -| CM_Get_DevNode_PropertyW | 不存在时,调用CM_Get_DevNode_Property_ExW。 -| CM_Set_DevNode_PropertyW | 不存在时,调用CM_Set_DevNode_Property_ExW。 - -## Crypt32.dll -| 函数 | Fallback -| ---- | ----------- -| CryptProtectMemory | 不存在时,返回TRUE。 -| CryptUnprotectMemory | 不存在时,返回TRUE。 -| CryptBinaryToStringW(A) | 为Windows XP模拟 CRYPT_STRING_NOCRLF。 - -## d3d9.dll -| 函数 | Fallback -| ---- | ----------- -| Direct3DCreate9Ex | 不存在时,返回 `D3DERR_NOTAVAILABLE`。 - -## d3d11.dll -| 函数 | Fallback -| ---- | ----------- -| D3D11CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 - -## d3d12.dll -| 函数 | Fallback -| ---- | ----------- -| D3D12CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 - -## DbgHelp.dll -| 函数 | Fallback -| ---- | ----------- -| SymSetSearchPathW | 不存在时,调用SymSetSearchPath。 -| SymGetSearchPathW | 不存在时,调用SymGetSearchPath。 - -## dwmapi.dll -| 函数 | Fallback -| ---- | ----------- -| DwmEnableBlurBehindWindow | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmIsCompositionEnabled | 不存在时,总是返回组合层已关闭。 -| DwmEnableComposition | 不存在时,如果尝试开启组合,那么返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用),其他情况返回 S_OK_。 -| DwmExtendFrameIntoClientArea | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmDefWindowProc | 不存在时,返回 FALSE。 -| DwmGetColorizationColor | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmGetWindowAttribute | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmSetWindowAttribute | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmFlush | 不存在时,返回 `S_OK_`。 -| DwmGetCompositionTimingInfo | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmInvalidateIconicBitmaps | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmSetIconicLivePreviewBitmap | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 -| DwmSetIconicThumbnail | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 - - -## dwrite.dll -| 函数 | Fallback -| ---- | ----------- -| DWriteCreateFactory | 不存在时,返回 `E_NOINTERFACE`。
此外NT6或者更高版本提供IDWriteFactory3模拟。 - -## dxgi.dll -| 函数 | Fallback -| ---- | ----------- -| CreateDXGIFactory | 返回 `DXGI_ERROR_UNSUPPORTED`。 -| CreateDXGIFactory1 | 调用 CreateDXGIFactory。 -| CreateDXGIFactory2 | 调用 CreateDXGIFactory1。 - -## dxva2.dll -| 函数 | Fallback -| ---- | ----------- -| DXVA2CreateVideoService | 不存在时,返回 `E_NOINTERFACE`。 - -## esent.dll -| 函数 | Fallback -| ---- | ----------- -| JetAddColumnA | 调用JetAddColumn。 -| JetAddColumnA | 调用JetAddColumn。 -| JetAttachDatabaseA | 调用JetAttachDatabase。 -| JetAttachDatabase2A | 调用JetAttachDatabase2。 -| JetAttachDatabaseWithStreamingA | 调用JetAttachDatabaseWithStreaming。 -| JetBackupA | 调用JetBackup。 -| JetBackupInstanceA | 调用JetBackupInstance。 -| JetBeginSessionA | 调用JetBeginSession。 -| JetCompactA | 调用JetCompact。 -| JetConvertDDLA | 调用JetConvertDDL。 -| JetCreateDatabaseA | 调用JetCreateDatabase。 -| JetCreateDatabase2A | 调用JetCreateDatabase2。 -| JetCreateDatabaseWithStreamingA | 调用JetCreateDatabaseWithStreaming。 -| JetCreateIndexA | 调用JetCreateIndex。 -| JetCreateIndex2A | 调用JetCreateIndex2。 -| JetCreateInstanceA | 调用JetCreateInstance。 -| JetCreateInstance2A | 调用JetCreateInstance2。 -| JetCreateTableA | 调用JetCreateTable。 -| JetCreateTableColumnIndexA | 调用JetCreateTableColumnIndex。 -| JetCreateTableColumnIndex2A | 调用JetCreateTableColumnIndex2。 -| JetDBUtilitiesA | 调用JetDBUtilities。 -| JetDefragmentA | 调用JetDefragment。 -| JetDefragment2A | 调用JetDefragment2。 -| JetDeleteColumnA | 调用JetDeleteColumn。 -| JetDeleteColumn2A | 调用JetDeleteColumn2。 -| JetDeleteIndexA | 调用JetDeleteIndex。 -| JetDeleteTableA | 调用JetDeleteTable。 -| JetDetachDatabaseA | 调用JetDetachDatabase。 -| JetDetachDatabase2A | 调用JetDetachDatabase2。 -| JetEnableMultiInstanceA | 调用JetEnableMultiInstance。 -| JetExternalRestoreA | 调用JetExternalRestore。 -| JetExternalRestore2A | 调用JetExternalRestore2。 -| JetGetAttachInfoA | 调用JetGetAttachInfo。 -| JetGetAttachInfoInstanceA | 调用JetGetAttachInfoInstance。 -| JetGetColumnInfoA | 调用JetGetColumnInfo。 -| JetGetCurrentIndexA | 调用JetGetCurrentIndex。 -| JetGetDatabaseFileInfoA | 调用JetGetDatabaseFileInfo。 -| JetGetDatabaseInfoA | 调用JetGetDatabaseInfo。 -| JetGetIndexInfoA | 调用JetGetIndexInfo。 -| JetGetInstanceInfoA | 调用JetGetInstanceInfo。 -| JetGetLogInfoA | 调用JetGetLogInfo。 -| JetGetLogInfoInstanceA | 调用JetGetLogInfoInstance。 -| JetGetLogInfoInstance2A | 调用JetGetLogInfoInstance2。 -| JetGetObjectInfoA | 调用JetGetObjectInfo。 -| JetGetSystemParameterA | 调用JetGetSystemParameter。 -| JetGetTableColumnInfoA | 调用JetGetTableColumnInfo。 -| JetGetTableIndexInfoA | 调用JetGetTableIndexInfo。 -| JetGetTableInfoA | 调用JetGetTableInfo。 -| JetGetTruncateLogInfoInstanceA | 调用JetGetTruncateLogInfoInstance。 -| JetInit3A | 调用JetInit3。 -| JetOpenDatabaseA | 调用JetOpenDatabase。 -| JetOpenFileA | 调用JetOpenFile。 -| JetOpenFileInstanceA | 调用JetOpenFileInstance。 -| JetOpenFileSectionInstanceA | 调用JetOpenFileSectionInstance。 -| JetOpenTableA | 调用JetOpenTable。 -| JetOSSnapshotFreezeA | 调用JetOSSnapshotFreeze。 -| JetRenameColumnA | 调用JetRenameColumn。 -| JetRenameTableA | 调用JetRenameTable。 -| JetRestoreA | 调用JetRestore。 -| JetRestore2A | 调用JetRestore2。 -| JetRestoreInstanceA | 调用JetRestoreInstance。 -| JetSetColumnDefaultValueA | 调用JetSetColumnDefaultValue。 -| JetSetCurrentIndexA | 调用JetSetCurrentIndex。 -| JetSetCurrentIndex2A | 调用JetSetCurrentIndex2。 -| JetSetCurrentIndex3A | 调用JetSetCurrentIndex3。 -| JetSetCurrentIndex4A | 调用JetSetCurrentIndex4。 -| JetSetDatabaseSizeA | 调用JetSetDatabaseSize。 -| JetSetSystemParameterA | 调用JetSetSystemParameter。 -| JetSnapshotStartA | 调用JetSnapshotStart。 -| JetUpgradeDatabaseA | 调用JetUpgradeDatabase。 -| JetAttachDatabase2W | 不存在时,调用JetAttachDatabase2A。 -| JetBeginSessionW | 不存在时,调用JetBeginSessionA。 -| JetCreateInstanceW | 不存在时,调用JetCreateInstanceA。 -| JetGetTableColumnInfoW | 不存在时,调用JetGetTableColumnInfoA。 -| JetOpenDatabaseW | 不存在时,调用JetOpenDatabaseA。 -| JetOpenTableW | 不存在时,调用JetOpenTableA。 -| JetSetSystemParameterW | 不存在时,调用JetSetSystemParameterA。 -| JetGetSystemParameterW | 不存在时,调用JetGetSystemParameterA。 - -## iphlpapi.dll -| 函数 | Fallback -| ---- | ----------- -| GetIfTable2 | 不存在时,调用GetIfTable,并使用HeapAlloc申请内存。 -| GetIfTable2Ex | 不存在时,调用GetIfTable,并使用HeapAlloc申请内存。 -| GetIfEntry2 | 不存在时,调用GetIfEntry。 -| GetIfEntry2Ex | 不存在时,调用GetIfEntry2。 -| FreeMibTable | 不存在时,调用HeapFree。 -| ConvertInterfaceIndexToLuid | 不存在时,调用GetIfEntry。 -| ConvertInterfaceLuidToNameW(A) | 不存在时,内部实现。 -| ConvertInterfaceNameToLuidW(A) | 不存在时,内部实现。 -| if_nametoindex | 不存在时,调用GetIfEntry。 -| if_indextoname | 不存在时,调用ConvertInterfaceIndexToLuid、ConvertInterfaceLuidToNameA。 -| ConvertInterfaceLuidToGuid | 不存在时,调用GetIfEntry。 -| ConvertInterfaceLuidToIndex | 不存在时,内部实现。 -| * NotifyIpInterfaceChange | 什么也不做,假装成功。 -| CancelMibChangeNotify2 | 什么也不做,假装成功。 - -## kernel32.dll -| 函数 | Fallback -| ---- | ----------- -| DecodePointer | 不存在时,返回指针本身。 -| EncodePointer | 不存在时,返回指针本身。 -| Wow64DisableWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 -| Wow64RevertWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 -| Wow64EnableWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 -| IsWow64Process2 | 不存在时,调用IsWow64Process。 -| IsWow64GuestMachineSupported | 不存在时,调用GetNativeSystemInfo。 -| GetTickCount64 | 不存在时,调用GetTickCount。 -| GetSystemTimePreciseAsFileTime | 不存在时,调用GetSystemTimeAsFileTime。 -| InitializeCriticalSectionEx | 不存在时,调用InitializeCriticalSectionAndSpinCount。 -| InitOnceInitialize | 初始化为 INIT_ONCE_STATIC_INIT。 -| InitOnceBeginInitialize | 不存在时,调用NtWaitForKeyedEvent。 -| InitOnceComplete | 不存在时,调用NtReleaseKeyedEvent。 -| InitOnceExecuteOnce | 不存在时,调用NtWaitForKeyedEvent以及NtReleaseKeyedEvent。 -| LocaleNameToLCID | 不存在时,查LocaleNameToLcidTable。 -| LCIDToLocaleName | 不存在时,查LcidToLocaleNameTable。 -| GetLocaleInfoEx | 不存在时,调用GetLocaleInfoW。 -| GetDateFormatEx | 不存在时,调用GetDateFormatW。 -| GetTimeFormatEx | 不存在时,调用GetTimeFormatW。 -| GetNumberFormatEx | 不存在时,调用GetNumberFormatW。 -| GetCurrencyFormatEx | 不存在时,调用GetCurrencyFormatW。 -| GetUserDefaultLocaleName | 不存在时,调用LCIDToLocaleName。 -| GetSystemDefaultLocaleName | 不存在时,调用LCIDToLocaleName。 -| EnumCalendarInfoExEx | 不存在时,调用EnumCalendarInfoExW。 -| EnumDateFormatsExEx | 不存在时,调用EnumDateFormatsExW。 -| LCMapStringEx | 不存在时,调用LCMapStringW。 -| GetFileInformationByHandleEx | 不存在时,调用NtQueryInformationFile 或者 NtQueryDirectoryFile。 -| SetFileInformationByHandle | 不存在时,调用NtSetInformationFile。 -| GetFinalPathNameByHandleW(A) | 不存在时,调用NtQueryObject以及NtQueryInformationFile。 -| GetLogicalProcessorInformation | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 -| GetLogicalProcessorInformationEx | 不存在时,调用GetLogicalProcessorInformation。 -| GetNumaHighestNodeNumber | 不存在时,返回0。 -| RaiseFailFastException | 不存在时,调用TerminateProcess。 -| GetThreadId | 不存在时,调用NtQueryInformationThread。 -| GetProcessIdOfThread | 不存在时,调用NtQueryInformationThread。 -| GetProcessId | 不存在时,调用NtQueryInformationProcess。 -| QueryThreadCycleTime | 不存在时,调用GetThreadTimes。 -| QueryProcessCycleTime | 不存在时,调用GetProcessTimes。 -| K32EnumProcessModules | 调用EnumProcessModules。 -| K32EnumProcessModulesEx | 调用EnumProcessModulesEx。 -| K32GetModuleBaseNameW(A) | 调用GetModuleBaseNameW(A)。 -| K32GetModuleFileNameExW(A) | 调用K32GetModuleFileNameExW(A)。 -| K32EmptyWorkingSet | 调用EmptyWorkingSet。 -| K32QueryWorkingSet | 调用QueryWorkingSet。 -| K32QueryWorkingSetEx | 调用QueryWorkingSetEx。 -| K32InitializeProcessForWsWatch | 调用InitializeProcessForWsWatch。 -| K32GetWsChanges | 调用GetWsChanges。 -| K32GetWsChangesEx | 调用GetWsChangesEx。 -| K32GetMappedFileNameW(A) | 调用GetMappedFileNameW(A)。 -| K32EnumDeviceDrivers | 调用EnumDeviceDrivers。 -| K32GetDeviceDriverBaseNameW(A) | 调用GetDeviceDriverBaseNameW(A)。 -| K32GetDeviceDriverFileNameW(A) | 调用GetDeviceDriverFileNameW(A)。 -| K32GetPerformanceInfo | 调用GetPerformanceInfo。 -| K32EnumPageFilesW(A) | 调用EnumPageFilesW(A)。 -| K32GetProcessImageFileNameW(A) | 调用GetProcessImageFileNameW(A)。 -| K32GetProcessMemoryInfo | 调用GetProcessMemoryInfo。 -| K32EnumProcesses | 调用EnumProcesses。 -| K32GetModuleInformation | 调用GetModuleInformation。 -| QueryFullProcessImageNameW(A) | 不存在时,调用GetProcessImageFileNameW(A) 或者 GetModuleFileNameExW(A)。 -| CreateFile2 | 不存在时,调用CreateFileW。 -| CreateEventExW(A) | 不存在时,调用CreateEventW(A)。 -| CreateMutexExW(A) | 不存在时,调用CreateMutexW(A)。 -| CreateSemaphoreExW | 不存在时,调用CreateSemaphoreW。 -| CreateWaitableTimerExW | 不存在时,调用CreateWaitableTimerW。 -| InterlockedCompareExchange64 | 调用内部函数_InterlockedCompareExchange64。 -| SetThreadErrorMode | 不存在时,调用SetErrorMode。 -| GetThreadErrorMode | 不存在时,调用GetErrorMode。 -| GetErrorMode | 不存在时,调用NtQueryInformationProcess。 -| InitializeSRWLock | 初始化为 RTL_SRWLOCK_INIT。 -| AcquireSRWLockExclusive | 不存在时,调用NtWaitForKeyedEvent。 -| TryAcquireSRWLockExclusive | 不存在时,调用InterlockedBitTestAndSet(64)。 -| ReleaseSRWLockExclusive | 不存在时,调用NtReleaseKeyedEvent。 -| AcquireSRWLockShared | 不存在时,调用NtWaitForKeyedEvent。 -| TryAcquireSRWLockShared | 不存在时,调用InterlockedCompareExchange。 -| ReleaseSRWLockShared | 不存在时,调用NtReleaseKeyedEvent。 -| InitializeConditionVariable | 初始化为 CONDITION_VARIABLE_INIT。 -| SleepConditionVariableCS | 不存在时,调用NtWaitForKeyedEvent。 -| SleepConditionVariableSRW | 不存在时,调用NtWaitForKeyedEvent。 -| WakeConditionVariable | 不存在时,调用NtReleaseKeyedEvent。 -| WakeAllConditionVariable | 不存在时,调用NtReleaseKeyedEvent。 -| InitializeSynchronizationBarrier | 不存在时,调用CreateEvent。 -| EnterSynchronizationBarrier | 不存在时,调用WaitForSingleObject。 -| DeleteSynchronizationBarrier | 不存在时,调用CloseHandle。 -| WaitOnAddress | 不存在时,调用NtWaitForKeyedEvent。警告,此函数请勿跨模块使用!!! -| WakeByAddressSingle | 不存在时,调用NtReleaseKeyedEvent。警告,此函数请勿跨模块使用!!! -| WakeByAddressAll | 不存在时,调用NtReleaseKeyedEvent。警告,此函数请勿跨模块使用!!! -| GetCurrentProcessorNumber | 不存在时,调用cpuid。 -| GetCurrentProcessorNumberEx | 不存在时,调用GetCurrentProcessorNumber。 -| GetNumaNodeProcessorMask | 不存在时,假定所有CPU都在当前Numa。 -| GetNumaNodeProcessorMaskEx | 不存在时,调用GetNumaNodeProcessorMask。 -| GetThreadGroupAffinity | 不存在时,调用NtQueryInformationThread。 -| SetThreadGroupAffinity | 不存在时,调用SetThreadAffinityMask。 -| *CancelIoEx | 不存在时,调用CancelIo。警告,会把此句柄的所有IO操作取消掉! -| *CancelSynchronousIo | 不存在时,仅返回失败。警告,实际无法取消! -| OpenFileById | 不存在时,调用NtCreateFile。 -| CreateSymbolicLinkW(A) | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 -| ReOpenFile | 不存在时,调用NtCreateFile。 -| CompareStringEx | 不存在时,调用CompareStringW。 -| CompareStringOrdinal | 不存在时,使用内置UnicodeCaseTableData实现。 -| SetFilePointerEx | 不存在时,调用SetFilePointer。 -| GetModuleHandleExW(A) | 不存在时,调用GetModuleHandleW(A)。 -| WTSGetActiveConsoleSessionId | 不存在时,直接返回 0。 -| GetNativeSystemInfo | 不存在时,调用GetSystemInfo。 -| InitializeSListHead | 直接初始化为 0。 -| InterlockedFlushSList | 不存在时,调用lock cmpxchg8b指令。 -| QueryDepthSList | 不存在时,直接返回Depth。 -| InterlockedPushEntrySList | 不存在时,调用lock cmpxchg8b指令。 -| InterlockedPopEntrySList | 不存在时,调用lock cmpxchg8b指令。 -| GetNumaProximityNodeEx | 不存在时,调用GetNumaProximityNode。 -| GetNumaProcessorNode | 不存在时,假定所有CPU都在节点 0。 -| GetNumaNodeNumberFromHandle | 不存在时,假定所有CPU都在节点 0。 -| GetNumaProcessorNodeEx | 不存在时,调用 GetNumaProcessorNode 。 -| GetNumaAvailableMemoryNode | 不存在时,假定所有内存都属于节点0 。 -| GetNumaAvailableMemoryNodeEx | 不存在时,调用 GetNumaAvailableMemoryNode 。 -| GetNumaProximityNode | 不存在时,假定都是节点0 。 -| AllocateUserPhysicalPagesNuma | 不存在时,调用 AllocateUserPhysicalPages 。 -| MapViewOfFileExNuma | 不存在时,调用 MapViewOfFileEx。 -| VirtualAllocExNuma | 不存在时,调用 VirtualAllocEx 。 -| CreateFileMappingNumaW(A) | 不存在时,调用 CreateFileMappingW(A) 。 -| GetMaximumProcessorCount | 不存在时,调用 GetSystemInfo 。 -| GetActiveProcessorCount | 不存在时,调用 GetSystemInfo 。 -| GetActiveProcessorGroupCount | 不存在时,假定为1 。 -| GetMaximumProcessorGroupCount | 不存在时,假定为1 。 -| GetMemoryErrorHandlingCapabilities | 不存在时,直接报告不支持任何特性。 -| VirtualAllocFromApp | 不存在时,调用 VirtualAlloc 。 -| VirtualAlloc2 | 不存在时,调用 VirtualAllocExNuma 以及 VirtualAllocEx 。 -| VirtualAlloc2FromApp | 不存在时,调用 VirtualAllocExNuma 以及 VirtualAllocEx 。 -| CreateFileMappingFromApp | 不存在时,调用 CreateFileMappingW 。 -| CreateFileMapping2 | 不存在时,调用 CreateFileMappingNumaW 以及 CreateFileMappingW 。 -| MapViewOfFileFromApp | 不存在时,调用 MapViewOfFile 。 -| UnmapViewOfFileEx | 不存在时,调用 UnmapViewOfFile 。 -| VirtualProtectFromApp | 不存在时,调用 VirtualProtect 。 -| OpenFileMappingFromApp | 不存在时,调用 OpenFileMappingW 。 -| FlushProcessWriteBuffers | 不存在时,调用VirtualProtect。 -| FlsAlloc | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! -| FlsFree | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! -| FlsGetValue | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! -| FlsSetValue | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! -| IsThreadAFiber | 不存在时,调用 GetCurrentFiber。 -| ConvertThreadToFiberEx | 不存在时,调用 ConvertThreadToFiber。 -| GetDynamicTimeZoneInformation | 不存在时,调用 GetTimeZoneInformation。 -| SetDynamicTimeZoneInformation | 不存在时,调用 SetTimeZoneInformation。 -| GetProductInfo | 不存在时,调用 GetVersionExW。 -| EnumSystemLocalesEx | 不存在时,调用 EnumSystemLocalesW。 -| GetThreadPreferredUILanguages | 不存在时,调用 GetThreadLocale、GetUserDefaultLangID以及GetSystemDefaultLangID。 -| GetThreadUILanguage | 不存在时,调用 GetThreadLocale。 -| ResolveLocaleName | 不存在时,调用 LocaleNameToLCID以及LCIDToLocaleName。 -| InitializeProcThreadAttributeList | 不存在时,内部实现。 -| DeleteProcThreadAttributeList | 不存在时,内部实现。 -| UpdateProcThreadAttribute | 不存在时,内部实现。PROC_THREAD_ATTRIBUTE_PARENT_PROCESS与PROC_THREAD_ATTRIBUTE_HANDLE_LIST特性会被忽略处理。 -| GetLargePageMinimum | 不存在时,假定为0 。 -| SetThreadStackGuarantee | 不存在时,调用VirtualAlloc。 -| SetCoalescableTimer | 不存在时,调用SetTimer。 -| SetWaitableTimerEx | 不存在时,调用SetWaitableTimer。 -| EnumResourceLanguagesExW(A) | 不存在时,调用EnumResourceLanguagesW(A)。 -| DiscardVirtualMemory | 不存在时,调用VirtualAlloc MEM_RESET。 -| OfferVirtualMemory | 不存在时,返回ERROR_SUCCESS。 -| ReclaimVirtualMemory | 不存在时,返回ERROR_SUCCESS。 -| PrefetchVirtualMemory | 不存在时,返回ERROR_SUCCESS。 -| GetProcessMitigationPolicy | 不存在时,调用NtQueryInformationProcess。 -| SetProcessMitigationPolicy | 不存在时,调用NtSetInformationProcess。 -| SetProcessInformation | 不存在时,调用NtSetInformationProcess。 -| GetThreadInformation | 不存在时,调用NtQueryInformationThread。 -| SetThreadInformation | 不存在时,调用NtSetInformationThread。 -| PowerCreateRequest | 不存在时,内部实现。 -| PowerSetRequest | 不存在时,调用 SetThreadExecutionState。 -| PowerClearRequest | 不存在时,调用 SetThreadExecutionState。 -| TzSpecificLocalTimeToSystemTime | 不存在时,内部实现。 -| TzSpecificLocalTimeToSystemTimeEx | 不存在时,内部实现。 -| GetFirmwareType | 不存在时,调用NtQuerySystemInformation。 -| IsNativeVhdBoot | 不存在时,调用NtQuerySystemInformation。 -| RtlCaptureStackBackTrace | 调用ntdll.RtlCaptureStackBackTrace。 -| SetFileCompletionNotificationModes | 不存在时,什么也不做。 -| GetQueuedCompletionStatusEx | 不存在时,调用 GetQueuedCompletionStatus。 -| FindFirstFileEx(W/A) | Windows XP、Vista兼容 FIND_FIRST_EX_LARGE_FETCH、FindExInfoStandard参数。 -| GetProcessGroupAffinity | 不存在时,始终认为只有一组CPU。 -| QueryUnbiasedInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值模拟UnbiasedInterruptTime。 -| FindStringOrdinal | 不存在时,调用CompareStringOrdinal。 -| GetEnabledXStateFeatures | 不存在时,调用IsProcessorFeaturePresent。 -| SetXStateFeaturesMask | 不存在时,内部实现。 -| InitializeContext | 不存在时,内部实现。 -| InitializeContext2 | 不存在时,调用InitializeContext。 -| LocateXStateFeature | 不存在时,内部实现。 -| CopyContext | 不存在时,内部实现。 -| QueryIdleProcessorCycleTimeEx | 不存在时,调用QueryIdleProcessorCycleTime。 -| QueryIdleProcessorCycleTime | 不存在时,随便返回一组数字代表当前进程空闲时间。 -| SetThreadIdealProcessorEx | 不存在时,调用SetThreadIdealProcessor。 -| GetThreadIdealProcessorEx | 不存在时,调用SetThreadIdealProcessor。 -| GetUserPreferredUILanguages | 不存在时,调用GetThreadPreferredUILanguages。 -| EnumTimeFormatsEx | 不存在时,调用EnumTimeFormatsW。 -| GetCalendarInfoEx | 不存在时,调用GetCalendarInfoW。 -| GetNLSVersionEx | 不存在时,返回一个假版本。 -| IsNLSDefinedString | 不存在时,调用GetStringTypeW。 -| FindNLSStringEx | 调用 CompareStringW。 -| SetProcessWorkingSetSizeEx | 不存在时,调用SetProcessWorkingSetSize。 -| GetProcessWorkingSetSizeEx | 不存在时,调用GetProcessWorkingSetSize。 -| GetTimeZoneInformationForYear | 不存在时,直接读取`Time Zones`注册表。 -| SetProcessDEPPolicy | 不存在时,调用NtSetInformationProcess。 -| GetSystemDEPPolicy | 不存在时,返回总是关闭。 -| DisableThreadLibraryCalls | 不存在时,始终返回成功。 -| CreateRemoteThreadEx | 不存在时,调用CreateRemoteThread。 -| WerRegisterRuntimeExceptionModule | 不存在时,返回S_OK。 -| WerUnregisterRuntimeExceptionModule | 不存在时,返回S_OK。 -| Wow64GetThreadContext | 不存在时,调用GetThreadContext或者返回ERROR_INVALID_PARAMETER。 -| SetDefaultDllDirectories | 不存在时,手工控制LoadLibrary加载顺序。 -| GetCurrentPackageFullName | 返回 APPMODEL_ERROR_NO_PACKAGE。 -| OpenProcess | 额外处理 PROCESS_QUERY_LIMITED_INFORMATION、PROCESS_SET_LIMITED_INFORMATION。 -| GetThreadDescription | 返回空字符串。 -| SetThreadDescription | 返回 `E_NOTIMPL`。 +# YY-Thunks Thunks 清单 + +此表展示了YY-Thunks(鸭船)可以解决的函数不存在问题,欢迎大家扩充! + +> 开头带`*`的函数并不建议使用,存在一些较大负面影响,仅用于编译通过处理,具体负面影响可参考注释内容。 + +## api-ms-win-core-handle-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| CompareObjectHandles | 不存在时,调用NtQueryObject以及DuplicateHandle。 + +## api-ms-win-core-path-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| PathIsUNCEx | 内部实现。 +| PathCchIsRoot | 内部实现。 +| PathCchAddBackslashEx | 内部实现。 +| PathCchAddBackslash | 调用PathCchAddBackslashEx。 +| PathCchRemoveBackslashEx | 内部实现。 +| PathCchRemoveBackslash | 调用PathCchRemoveBackslashEx。 +| PathCchSkipRoot | 内部实现。 +| PathCchStripToRoot | 内部实现。 +| PathCchRemoveFileSpec | 内部实现。 +| PathCchFindExtension | 内部实现。 +| PathCchAddExtension | 调用PathCchFindExtension。 +| PathCchRenameExtension | 调用PathCchFindExtension。 +| PathCchRemoveExtension | 调用PathCchFindExtension。 +| PathCchCanonicalizeEx | 不存在时,内部实现。 +| PathCchCanonicalize | 调用PathCchCanonicalizeEx。 +| PathCchCombineEx | 内部实现。 +| PathCchCombine | 调用PathCchCombineEx。 +| PathCchAppendEx | 调用PathCchCombineEx。 +| PathCchAppend | 调用PathCchAppendEx。 +| PathCchStripPrefix | 内部实现。 +| 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-threadpool-l1-2-0.dll +| 函数 | Fallback +| ---- | ----------- +| CreateThreadpoolWork | 不存在时,内部实现。 +| CloseThreadpoolWork | 不存在时,内部实现。 +| TrySubmitThreadpoolCallback | 不存在时,调用QueueUserWorkItem。 +| SubmitThreadpoolWork | 不存在时,调用QueueUserWorkItem。 +| WaitForThreadpoolWorkCallbacks | 不存在时,内部实现。 +| CreateThreadpoolTimer | 不存在时,内部实现。 +| CloseThreadpoolTimer | 不存在时,调用DeleteTimerQueueTimer。 +| SetThreadpoolTimer | 不存在时,调用CreateTimerQueueTimer。 +| WaitForThreadpoolTimerCallbacks | 不存在时,调用WaitForSingleObject。 +| SetEventWhenCallbackReturns | 不存在时,内部实现。 +| ReleaseSemaphoreWhenCallbackReturns | 不存在时,内部实现。 +| ReleaseMutexWhenCallbackReturns | 不存在时,内部实现。 +| LeaveCriticalSectionWhenCallbackReturns | 不存在时,内部实现。 +| FreeLibraryWhenCallbackReturns | 不存在时,内部实现。 +| CreateThreadpoolWait | 不存在时,内部实现。 +| CloseThreadpoolWait | 不存在时,调用UnregisterWait。 +| SetThreadpoolWait | 不存在时,调用RegisterWaitForSingleObject。 +| WaitForThreadpoolWaitCallbacks | 不存在时,调用WaitForSingleObject。 +| CreateThreadpoolIo | 不存在时,调用BindIoCompletionCallback。 +| CloseThreadpoolIo | 不存在时,内部实现。 +| StartThreadpoolIo | 不存在时,内部实现。 +| CancelThreadpoolIo | 不存在时,内部实现。 +| WaitForThreadpoolIoCallbacks | 不存在时,调用WaitForSingleObject。 +| CreateThreadpool | 不存在时,内部实现。 +| CloseThreadpool | 不存在时,内部实现。 +| SetThreadpoolThreadMaximum | 不存在时,内部实现,自己控制最大并行数量。 +| SetThreadpoolThreadMinimum | 不存在时,忽略,并总是返回成功。 +| CallbackMayRunLong | 不存在时,自己估算系统剩余可用线程数。 + +## api-ms-win-core-winrt-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| RoInitialize | 不存在时,调用 CoInitializeEx。 +| RoUninitialize | 不存在时,调用 CoUninitialize。 +| RoActivateInstance | 不存在时,返回 E_NOTIMPL。 +| RoRegisterActivationFactories | 不存在时,返回 E_NOTIMPL。 +| RoRevokeActivationFactories | 不存在时,什么也不做。 +| RoGetActivationFactory | 不存在时,返回 CLASS_E_CLASSNOTAVAILABLE +| RoRegisterForApartmentShutdown | 不存在时,返回 E_NOTIMPL。 +| RoUnregisterForApartmentShutdown | 不存在时,返回 E_NOTIMPL。 +| RoGetApartmentIdentifier | 不存在时,返回 E_NOTIMPL。 + +## api-ms-win-core-winrt-error-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| RoOriginateError | 不存在时,返回 TRUE. +| RoOriginateErrorW | 不存在时,返回 TRUE. + +## api-ms-win-core-winrt-string-l1-1-0.dll +| 函数 | Fallback +| ---- | ----------- +| WindowsCreateString | 不存在时,内部实现。 +| WindowsCreateStringReference | 不存在时,内部实现。 +| WindowsDeleteString | 不存在时,内部实现。 +| WindowsDuplicateString | 不存在时,内部实现。 +| WindowsGetStringLen | 不存在时,内部实现。 +| WindowsGetStringRawBuffer | 不存在时,内部实现。 +| WindowsIsStringEmpty | 不存在时,内部实现。 +| WindowsStringHasEmbeddedNull | 不存在时,内部实现。 +| WindowsCompareStringOrdinal | 不存在时,内部实现。 + +## advapi32.dll +| 函数 | Fallback +| ---- | ----------- +| RegDeleteKeyExW(A) | 不存在时,调用RegDeleteKeyW(A)。 +| RegSetKeyValueW(A) | 调用RegCreateKeyExW(A)以及RegSetValueExW(A)。 +| RegDeleteKeyValueW(A) | 调用RegOpenKeyExW(A)以及RegDeleteValueW(A)。 +| RegDeleteTreeW(A) | 调用SHDeleteKeyW(A)。 +| RegGetValueW(A) | 不存在时,调用RegQueryValueExW(A)。 +| RegCopyTreeW(A) | 不存在时,调用SHCopyKeyW(A)。 +| EventSetInformation | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventActivityIdControl | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventRegister | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventUnregister | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EnumerateTraceGuidsEx | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventEnabled | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventWrite | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventWriteTransfer | 不存在时,返回ERROR_NOT_SUPPORTED。 +| EventWriteEx | 不存在时,调用EventWriteTransfer。 +| EventWriteString | 不存在时,返回ERROR_NOT_SUPPORTED。 +| GetDynamicTimeZoneInformationEffectiveYears| 不存在时,直接读取`Time Zones`注册表。 +| AddMandatoryAce | 不存在时,调用RtlCopySid。 +| GetTokenInformation | 返回假装的 TokenVirtualizationAllowed、TokenAppContainerSid等。 + +## bcrypt.dll +| 函数 | Fallback +| ---- | ----------- +| BCryptOpenAlgorithmProvider | 不存在时,调用CryptAcquireContextW。目前支持的算法有:RC2、RC4、AES、DES、3DES、3DES-112、MD2、MD4、MD5、SHA1、SHA256、SHA384、SHA512、RNG、FIPS186DSARNG、DUALECRNG。 +| BCryptCloseAlgorithmProvider | 不存在时,调用CryptReleaseContext。 +| BCryptGenRandom | 不存在时,调用RtlGenRandom。 +| BCryptGetProperty | 不存在时,调用CryptGetKeyParam。 +| BCryptSetProperty | 不存在时,调用CryptSetKeyParam。 +| BCryptCreateHash | 不存在时,调用CryptCreateHash。 +| BCryptDestroyHash | 不存在时,调用CryptDestroyHash。 +| BCryptHashData | 不存在时,调用CryptHashData。 +| BCryptFinishHash | 不存在时,调用CryptGetHashParam。 +| BCryptDeriveKeyPBKDF2 | 不存在时,调用BCryptHashData。 +| BCryptDeriveKeyCapi | 不存在时,调用BCryptHashData。 +| BCryptEncrypt | 不存在时,调用CryptEncrypt。 +| BCryptDecrypt | 不存在时,调用CryptDecrypt。 +| BCryptGenerateSymmetricKey | 不存在时,调用CryptImportKey。 +| BCryptDestroyKey | 不存在时,调用CryptDestroyKey。 +| BCryptExportKey | 不存在时,调用CryptExportKey。 +| BCryptImportKey | 不存在时,调用CryptImportKey。 + +## bcryptprimitives.dll +| 函数 | Fallback +| ---- | ----------- +| ProcessPrng | 不存在时调用,RtlGenRandom。 + +## bluetoothapis.dll +| 函数 | Fallback +| ---- | ----------- +| BluetoothGATTGetCharacteristicValue | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTGetCharacteristics | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTGetDescriptors | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTGetServices | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTRegisterEvent | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTSetCharacteristicValue | 不存在时,返回ERROR_NOT_SUPPORTED。 +| BluetoothGATTSetDescriptorValue | 不存在时,返回ERROR_NOT_SUPPORTED。 + +## CfgMgr32.dll +| 函数 | Fallback +| ---- | ----------- +| CM_Get_DevNode_Property_ExW | 不存在时,调用CM_Get_DevNode_Registry_PropertyW。 +| CM_Set_DevNode_Property_ExW | 不存在时,调用CM_Set_DevNode_Registry_PropertyW。 +| CM_Get_DevNode_PropertyW | 不存在时,调用CM_Get_DevNode_Property_ExW。 +| CM_Set_DevNode_PropertyW | 不存在时,调用CM_Set_DevNode_Property_ExW。 + +## Crypt32.dll +| 函数 | Fallback +| ---- | ----------- +| CryptProtectMemory | 不存在时,返回TRUE。 +| CryptUnprotectMemory | 不存在时,返回TRUE。 +| CryptBinaryToStringW(A) | 为Windows XP模拟 CRYPT_STRING_NOCRLF。 + +## d3d9.dll +| 函数 | Fallback +| ---- | ----------- +| Direct3DCreate9Ex | 不存在时,返回 `D3DERR_NOTAVAILABLE`。 + +## d3d11.dll +| 函数 | Fallback +| ---- | ----------- +| D3D11CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 + +## d3d12.dll +| 函数 | Fallback +| ---- | ----------- +| D3D12CreateDevice | 不存在时,返回 `E_NOINTERFACE`。 + +## DbgHelp.dll +| 函数 | Fallback +| ---- | ----------- +| SymSetSearchPathW | 不存在时,调用SymSetSearchPath。 +| SymGetSearchPathW | 不存在时,调用SymGetSearchPath。 + +## dwmapi.dll +| 函数 | Fallback +| ---- | ----------- +| DwmEnableBlurBehindWindow | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmIsCompositionEnabled | 不存在时,总是返回组合层已关闭。 +| DwmEnableComposition | 不存在时,如果尝试开启组合,那么返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用),其他情况返回 S_OK_。 +| DwmExtendFrameIntoClientArea | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmDefWindowProc | 不存在时,返回 FALSE。 +| DwmGetColorizationColor | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmGetWindowAttribute | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmSetWindowAttribute | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmFlush | 不存在时,返回 `S_OK_`。 +| DwmGetCompositionTimingInfo | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmInvalidateIconicBitmaps | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmSetIconicLivePreviewBitmap | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 +| DwmSetIconicThumbnail | 不存在时,返回 `DWM_E_COMPOSITIONDISABLED`(表示DWM已禁用)。 + + +## dwrite.dll +| 函数 | Fallback +| ---- | ----------- +| DWriteCreateFactory | 不存在时,返回 `E_NOINTERFACE`。
此外NT6或者更高版本提供IDWriteFactory3模拟。 + +## dxgi.dll +| 函数 | Fallback +| ---- | ----------- +| CreateDXGIFactory | 返回 `DXGI_ERROR_UNSUPPORTED`。 +| CreateDXGIFactory1 | 调用 CreateDXGIFactory。 +| CreateDXGIFactory2 | 调用 CreateDXGIFactory1。 + +## dxva2.dll +| 函数 | Fallback +| ---- | ----------- +| DXVA2CreateVideoService | 不存在时,返回 `E_NOINTERFACE`。 + +## esent.dll +| 函数 | Fallback +| ---- | ----------- +| JetAddColumnA | 调用JetAddColumn。 +| JetAddColumnA | 调用JetAddColumn。 +| JetAttachDatabaseA | 调用JetAttachDatabase。 +| JetAttachDatabase2A | 调用JetAttachDatabase2。 +| JetAttachDatabaseWithStreamingA | 调用JetAttachDatabaseWithStreaming。 +| JetBackupA | 调用JetBackup。 +| JetBackupInstanceA | 调用JetBackupInstance。 +| JetBeginSessionA | 调用JetBeginSession。 +| JetCompactA | 调用JetCompact。 +| JetConvertDDLA | 调用JetConvertDDL。 +| JetCreateDatabaseA | 调用JetCreateDatabase。 +| JetCreateDatabase2A | 调用JetCreateDatabase2。 +| JetCreateDatabaseWithStreamingA | 调用JetCreateDatabaseWithStreaming。 +| JetCreateIndexA | 调用JetCreateIndex。 +| JetCreateIndex2A | 调用JetCreateIndex2。 +| JetCreateInstanceA | 调用JetCreateInstance。 +| JetCreateInstance2A | 调用JetCreateInstance2。 +| JetCreateTableA | 调用JetCreateTable。 +| JetCreateTableColumnIndexA | 调用JetCreateTableColumnIndex。 +| JetCreateTableColumnIndex2A | 调用JetCreateTableColumnIndex2。 +| JetDBUtilitiesA | 调用JetDBUtilities。 +| JetDefragmentA | 调用JetDefragment。 +| JetDefragment2A | 调用JetDefragment2。 +| JetDeleteColumnA | 调用JetDeleteColumn。 +| JetDeleteColumn2A | 调用JetDeleteColumn2。 +| JetDeleteIndexA | 调用JetDeleteIndex。 +| JetDeleteTableA | 调用JetDeleteTable。 +| JetDetachDatabaseA | 调用JetDetachDatabase。 +| JetDetachDatabase2A | 调用JetDetachDatabase2。 +| JetEnableMultiInstanceA | 调用JetEnableMultiInstance。 +| JetExternalRestoreA | 调用JetExternalRestore。 +| JetExternalRestore2A | 调用JetExternalRestore2。 +| JetGetAttachInfoA | 调用JetGetAttachInfo。 +| JetGetAttachInfoInstanceA | 调用JetGetAttachInfoInstance。 +| JetGetColumnInfoA | 调用JetGetColumnInfo。 +| JetGetCurrentIndexA | 调用JetGetCurrentIndex。 +| JetGetDatabaseFileInfoA | 调用JetGetDatabaseFileInfo。 +| JetGetDatabaseInfoA | 调用JetGetDatabaseInfo。 +| JetGetIndexInfoA | 调用JetGetIndexInfo。 +| JetGetInstanceInfoA | 调用JetGetInstanceInfo。 +| JetGetLogInfoA | 调用JetGetLogInfo。 +| JetGetLogInfoInstanceA | 调用JetGetLogInfoInstance。 +| JetGetLogInfoInstance2A | 调用JetGetLogInfoInstance2。 +| JetGetObjectInfoA | 调用JetGetObjectInfo。 +| JetGetSystemParameterA | 调用JetGetSystemParameter。 +| JetGetTableColumnInfoA | 调用JetGetTableColumnInfo。 +| JetGetTableIndexInfoA | 调用JetGetTableIndexInfo。 +| JetGetTableInfoA | 调用JetGetTableInfo。 +| JetGetTruncateLogInfoInstanceA | 调用JetGetTruncateLogInfoInstance。 +| JetInit3A | 调用JetInit3。 +| JetOpenDatabaseA | 调用JetOpenDatabase。 +| JetOpenFileA | 调用JetOpenFile。 +| JetOpenFileInstanceA | 调用JetOpenFileInstance。 +| JetOpenFileSectionInstanceA | 调用JetOpenFileSectionInstance。 +| JetOpenTableA | 调用JetOpenTable。 +| JetOSSnapshotFreezeA | 调用JetOSSnapshotFreeze。 +| JetRenameColumnA | 调用JetRenameColumn。 +| JetRenameTableA | 调用JetRenameTable。 +| JetRestoreA | 调用JetRestore。 +| JetRestore2A | 调用JetRestore2。 +| JetRestoreInstanceA | 调用JetRestoreInstance。 +| JetSetColumnDefaultValueA | 调用JetSetColumnDefaultValue。 +| JetSetCurrentIndexA | 调用JetSetCurrentIndex。 +| JetSetCurrentIndex2A | 调用JetSetCurrentIndex2。 +| JetSetCurrentIndex3A | 调用JetSetCurrentIndex3。 +| JetSetCurrentIndex4A | 调用JetSetCurrentIndex4。 +| JetSetDatabaseSizeA | 调用JetSetDatabaseSize。 +| JetSetSystemParameterA | 调用JetSetSystemParameter。 +| JetSnapshotStartA | 调用JetSnapshotStart。 +| JetUpgradeDatabaseA | 调用JetUpgradeDatabase。 +| JetAttachDatabase2W | 不存在时,调用JetAttachDatabase2A。 +| JetBeginSessionW | 不存在时,调用JetBeginSessionA。 +| JetCreateInstanceW | 不存在时,调用JetCreateInstanceA。 +| JetGetTableColumnInfoW | 不存在时,调用JetGetTableColumnInfoA。 +| JetOpenDatabaseW | 不存在时,调用JetOpenDatabaseA。 +| JetOpenTableW | 不存在时,调用JetOpenTableA。 +| JetSetSystemParameterW | 不存在时,调用JetSetSystemParameterA。 +| JetGetSystemParameterW | 不存在时,调用JetGetSystemParameterA。 + +## iphlpapi.dll +| 函数 | Fallback +| ---- | ----------- +| GetIfTable2 | 不存在时,调用GetIfTable,并使用HeapAlloc申请内存。 +| GetIfTable2Ex | 不存在时,调用GetIfTable,并使用HeapAlloc申请内存。 +| GetIfEntry2 | 不存在时,调用GetIfEntry。 +| GetIfEntry2Ex | 不存在时,调用GetIfEntry2。 +| FreeMibTable | 不存在时,调用HeapFree。 +| ConvertInterfaceIndexToLuid | 不存在时,调用GetIfEntry。 +| ConvertInterfaceLuidToNameW(A) | 不存在时,内部实现。 +| ConvertInterfaceNameToLuidW(A) | 不存在时,内部实现。 +| if_nametoindex | 不存在时,调用GetIfEntry。 +| if_indextoname | 不存在时,调用ConvertInterfaceIndexToLuid、ConvertInterfaceLuidToNameA。 +| ConvertInterfaceLuidToGuid | 不存在时,调用GetIfEntry。 +| ConvertInterfaceLuidToIndex | 不存在时,内部实现。 +| * NotifyIpInterfaceChange | 什么也不做,假装成功。 +| CancelMibChangeNotify2 | 什么也不做,假装成功。 + +## kernel32.dll +| 函数 | Fallback +| ---- | ----------- +| DecodePointer | 不存在时,返回指针本身。 +| EncodePointer | 不存在时,返回指针本身。 +| Wow64DisableWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 +| Wow64RevertWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 +| Wow64EnableWow64FsRedirection | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 +| IsWow64Process2 | 不存在时,调用IsWow64Process。 +| IsWow64GuestMachineSupported | 不存在时,调用GetNativeSystemInfo。 +| GetTickCount64 | 不存在时,调用GetTickCount。 +| GetSystemTimePreciseAsFileTime | 不存在时,调用GetSystemTimeAsFileTime。 +| InitializeCriticalSectionEx | 不存在时,调用InitializeCriticalSectionAndSpinCount。 +| InitOnceInitialize | 初始化为 INIT_ONCE_STATIC_INIT。 +| InitOnceBeginInitialize | 不存在时,调用NtWaitForKeyedEvent。 +| InitOnceComplete | 不存在时,调用NtReleaseKeyedEvent。 +| InitOnceExecuteOnce | 不存在时,调用NtWaitForKeyedEvent以及NtReleaseKeyedEvent。 +| LocaleNameToLCID | 不存在时,查LocaleNameToLcidTable。 +| LCIDToLocaleName | 不存在时,查LcidToLocaleNameTable。 +| GetLocaleInfoEx | 不存在时,调用GetLocaleInfoW。 +| GetDateFormatEx | 不存在时,调用GetDateFormatW。 +| GetTimeFormatEx | 不存在时,调用GetTimeFormatW。 +| GetNumberFormatEx | 不存在时,调用GetNumberFormatW。 +| GetCurrencyFormatEx | 不存在时,调用GetCurrencyFormatW。 +| GetUserDefaultLocaleName | 不存在时,调用LCIDToLocaleName。 +| GetSystemDefaultLocaleName | 不存在时,调用LCIDToLocaleName。 +| EnumCalendarInfoExEx | 不存在时,调用EnumCalendarInfoExW。 +| EnumDateFormatsExEx | 不存在时,调用EnumDateFormatsExW。 +| LCMapStringEx | 不存在时,调用LCMapStringW。 +| GetFileInformationByHandleEx | 不存在时,调用NtQueryInformationFile 或者 NtQueryDirectoryFile。 +| SetFileInformationByHandle | 不存在时,调用NtSetInformationFile。 +| GetFinalPathNameByHandleW(A) | 不存在时,调用NtQueryObject以及NtQueryInformationFile。 +| GetLogicalProcessorInformation | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 +| GetLogicalProcessorInformationEx | 不存在时,调用GetLogicalProcessorInformation。 +| GetNumaHighestNodeNumber | 不存在时,返回0。 +| RaiseFailFastException | 不存在时,调用TerminateProcess。 +| GetThreadId | 不存在时,调用NtQueryInformationThread。 +| GetProcessIdOfThread | 不存在时,调用NtQueryInformationThread。 +| GetProcessId | 不存在时,调用NtQueryInformationProcess。 +| QueryThreadCycleTime | 不存在时,调用GetThreadTimes。 +| QueryProcessCycleTime | 不存在时,调用GetProcessTimes。 +| K32EnumProcessModules | 调用EnumProcessModules。 +| K32EnumProcessModulesEx | 调用EnumProcessModulesEx。 +| K32GetModuleBaseNameW(A) | 调用GetModuleBaseNameW(A)。 +| K32GetModuleFileNameExW(A) | 调用K32GetModuleFileNameExW(A)。 +| K32EmptyWorkingSet | 调用EmptyWorkingSet。 +| K32QueryWorkingSet | 调用QueryWorkingSet。 +| K32QueryWorkingSetEx | 调用QueryWorkingSetEx。 +| K32InitializeProcessForWsWatch | 调用InitializeProcessForWsWatch。 +| K32GetWsChanges | 调用GetWsChanges。 +| K32GetWsChangesEx | 调用GetWsChangesEx。 +| K32GetMappedFileNameW(A) | 调用GetMappedFileNameW(A)。 +| K32EnumDeviceDrivers | 调用EnumDeviceDrivers。 +| K32GetDeviceDriverBaseNameW(A) | 调用GetDeviceDriverBaseNameW(A)。 +| K32GetDeviceDriverFileNameW(A) | 调用GetDeviceDriverFileNameW(A)。 +| K32GetPerformanceInfo | 调用GetPerformanceInfo。 +| K32EnumPageFilesW(A) | 调用EnumPageFilesW(A)。 +| K32GetProcessImageFileNameW(A) | 调用GetProcessImageFileNameW(A)。 +| K32GetProcessMemoryInfo | 调用GetProcessMemoryInfo。 +| K32EnumProcesses | 调用EnumProcesses。 +| K32GetModuleInformation | 调用GetModuleInformation。 +| QueryFullProcessImageNameW(A) | 不存在时,调用GetProcessImageFileNameW(A) 或者 GetModuleFileNameExW(A)。 +| CreateFile2 | 不存在时,调用CreateFileW。 +| CreateEventExW(A) | 不存在时,调用CreateEventW(A)。 +| CreateMutexExW(A) | 不存在时,调用CreateMutexW(A)。 +| CreateSemaphoreExW | 不存在时,调用CreateSemaphoreW。 +| CreateWaitableTimerExW | 不存在时,调用CreateWaitableTimerW。 +| InterlockedCompareExchange64 | 调用内部函数_InterlockedCompareExchange64。 +| SetThreadErrorMode | 不存在时,调用SetErrorMode。 +| GetThreadErrorMode | 不存在时,调用GetErrorMode。 +| GetErrorMode | 不存在时,调用NtQueryInformationProcess。 +| InitializeSRWLock | 初始化为 RTL_SRWLOCK_INIT。 +| AcquireSRWLockExclusive | 不存在时,调用NtWaitForKeyedEvent。 +| TryAcquireSRWLockExclusive | 不存在时,调用InterlockedBitTestAndSet(64)。 +| ReleaseSRWLockExclusive | 不存在时,调用NtReleaseKeyedEvent。 +| AcquireSRWLockShared | 不存在时,调用NtWaitForKeyedEvent。 +| TryAcquireSRWLockShared | 不存在时,调用InterlockedCompareExchange。 +| ReleaseSRWLockShared | 不存在时,调用NtReleaseKeyedEvent。 +| InitializeConditionVariable | 初始化为 CONDITION_VARIABLE_INIT。 +| SleepConditionVariableCS | 不存在时,调用NtWaitForKeyedEvent。 +| SleepConditionVariableSRW | 不存在时,调用NtWaitForKeyedEvent。 +| WakeConditionVariable | 不存在时,调用NtReleaseKeyedEvent。 +| WakeAllConditionVariable | 不存在时,调用NtReleaseKeyedEvent。 +| InitializeSynchronizationBarrier | 不存在时,调用CreateEvent。 +| EnterSynchronizationBarrier | 不存在时,调用WaitForSingleObject。 +| DeleteSynchronizationBarrier | 不存在时,调用CloseHandle。 +| WaitOnAddress | 不存在时,调用NtWaitForKeyedEvent。警告,此函数请勿跨模块使用!!! +| WakeByAddressSingle | 不存在时,调用NtReleaseKeyedEvent。警告,此函数请勿跨模块使用!!! +| WakeByAddressAll | 不存在时,调用NtReleaseKeyedEvent。警告,此函数请勿跨模块使用!!! +| GetCurrentProcessorNumber | 不存在时,调用cpuid。 +| GetCurrentProcessorNumberEx | 不存在时,调用GetCurrentProcessorNumber。 +| GetNumaNodeProcessorMask | 不存在时,假定所有CPU都在当前Numa。 +| GetNumaNodeProcessorMaskEx | 不存在时,调用GetNumaNodeProcessorMask。 +| GetThreadGroupAffinity | 不存在时,调用NtQueryInformationThread。 +| SetThreadGroupAffinity | 不存在时,调用SetThreadAffinityMask。 +| *CancelIoEx | 不存在时,调用CancelIo。警告,会把此句柄的所有IO操作取消掉! +| *CancelSynchronousIo | 不存在时,仅返回失败。警告,实际无法取消! +| OpenFileById | 不存在时,调用NtCreateFile。 +| CreateSymbolicLinkW(A) | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 +| ReOpenFile | 不存在时,调用NtCreateFile。 +| CompareStringEx | 不存在时,调用CompareStringW。 +| CompareStringOrdinal | 不存在时,使用内置UnicodeCaseTableData实现。 +| SetFilePointerEx | 不存在时,调用SetFilePointer。 +| GetModuleHandleExW(A) | 不存在时,调用GetModuleHandleW(A)。 +| WTSGetActiveConsoleSessionId | 不存在时,直接返回 0。 +| GetNativeSystemInfo | 不存在时,调用GetSystemInfo。 +| InitializeSListHead | 直接初始化为 0。 +| InterlockedFlushSList | 不存在时,调用lock cmpxchg8b指令。 +| QueryDepthSList | 不存在时,直接返回Depth。 +| InterlockedPushEntrySList | 不存在时,调用lock cmpxchg8b指令。 +| InterlockedPopEntrySList | 不存在时,调用lock cmpxchg8b指令。 +| GetNumaProximityNodeEx | 不存在时,调用GetNumaProximityNode。 +| GetNumaProcessorNode | 不存在时,假定所有CPU都在节点 0。 +| GetNumaNodeNumberFromHandle | 不存在时,假定所有CPU都在节点 0。 +| GetNumaProcessorNodeEx | 不存在时,调用 GetNumaProcessorNode 。 +| GetNumaAvailableMemoryNode | 不存在时,假定所有内存都属于节点0 。 +| GetNumaAvailableMemoryNodeEx | 不存在时,调用 GetNumaAvailableMemoryNode 。 +| GetNumaProximityNode | 不存在时,假定都是节点0 。 +| AllocateUserPhysicalPagesNuma | 不存在时,调用 AllocateUserPhysicalPages 。 +| MapViewOfFileExNuma | 不存在时,调用 MapViewOfFileEx。 +| VirtualAllocExNuma | 不存在时,调用 VirtualAllocEx 。 +| CreateFileMappingNumaW(A) | 不存在时,调用 CreateFileMappingW(A) 。 +| GetMaximumProcessorCount | 不存在时,调用 GetSystemInfo 。 +| GetActiveProcessorCount | 不存在时,调用 GetSystemInfo 。 +| GetActiveProcessorGroupCount | 不存在时,假定为1 。 +| GetMaximumProcessorGroupCount | 不存在时,假定为1 。 +| GetMemoryErrorHandlingCapabilities | 不存在时,直接报告不支持任何特性。 +| VirtualAllocFromApp | 不存在时,调用 VirtualAlloc 。 +| VirtualAlloc2 | 不存在时,调用 VirtualAllocExNuma 以及 VirtualAllocEx 。 +| VirtualAlloc2FromApp | 不存在时,调用 VirtualAllocExNuma 以及 VirtualAllocEx 。 +| CreateFileMappingFromApp | 不存在时,调用 CreateFileMappingW 。 +| CreateFileMapping2 | 不存在时,调用 CreateFileMappingNumaW 以及 CreateFileMappingW 。 +| MapViewOfFileFromApp | 不存在时,调用 MapViewOfFile 。 +| UnmapViewOfFileEx | 不存在时,调用 UnmapViewOfFile 。 +| VirtualProtectFromApp | 不存在时,调用 VirtualProtect 。 +| OpenFileMappingFromApp | 不存在时,调用 OpenFileMappingW 。 +| FlushProcessWriteBuffers | 不存在时,调用VirtualProtect。 +| FlsAlloc | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! +| FlsFree | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! +| FlsGetValue | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! +| FlsSetValue | 不存在时,使用Tls实现。警告,此函数请勿跨模块使用!!! +| IsThreadAFiber | 不存在时,调用 GetCurrentFiber。 +| ConvertThreadToFiberEx | 不存在时,调用 ConvertThreadToFiber。 +| GetDynamicTimeZoneInformation | 不存在时,调用 GetTimeZoneInformation。 +| SetDynamicTimeZoneInformation | 不存在时,调用 SetTimeZoneInformation。 +| GetProductInfo | 不存在时,调用 GetVersionExW。 +| EnumSystemLocalesEx | 不存在时,调用 EnumSystemLocalesW。 +| GetThreadPreferredUILanguages | 不存在时,调用 GetThreadLocale、GetUserDefaultLangID以及GetSystemDefaultLangID。 +| GetThreadUILanguage | 不存在时,调用 GetThreadLocale。 +| ResolveLocaleName | 不存在时,调用 LocaleNameToLCID以及LCIDToLocaleName。 +| InitializeProcThreadAttributeList | 不存在时,内部实现。 +| DeleteProcThreadAttributeList | 不存在时,内部实现。 +| UpdateProcThreadAttribute | 不存在时,内部实现。PROC_THREAD_ATTRIBUTE_PARENT_PROCESS与PROC_THREAD_ATTRIBUTE_HANDLE_LIST特性会被忽略处理。 +| GetLargePageMinimum | 不存在时,假定为0 。 +| SetThreadStackGuarantee | 不存在时,调用VirtualAlloc。 +| SetCoalescableTimer | 不存在时,调用SetTimer。 +| SetWaitableTimerEx | 不存在时,调用SetWaitableTimer。 +| EnumResourceLanguagesExW(A) | 不存在时,调用EnumResourceLanguagesW(A)。 +| DiscardVirtualMemory | 不存在时,调用VirtualAlloc MEM_RESET。 +| OfferVirtualMemory | 不存在时,返回ERROR_SUCCESS。 +| ReclaimVirtualMemory | 不存在时,返回ERROR_SUCCESS。 +| PrefetchVirtualMemory | 不存在时,返回ERROR_SUCCESS。 +| GetProcessMitigationPolicy | 不存在时,调用NtQueryInformationProcess。 +| SetProcessMitigationPolicy | 不存在时,调用NtSetInformationProcess。 +| SetProcessInformation | 不存在时,调用NtSetInformationProcess。 +| GetThreadInformation | 不存在时,调用NtQueryInformationThread。 +| SetThreadInformation | 不存在时,调用NtSetInformationThread。 +| PowerCreateRequest | 不存在时,内部实现。 +| PowerSetRequest | 不存在时,调用 SetThreadExecutionState。 +| PowerClearRequest | 不存在时,调用 SetThreadExecutionState。 +| TzSpecificLocalTimeToSystemTime | 不存在时,内部实现。 +| TzSpecificLocalTimeToSystemTimeEx | 不存在时,内部实现。 +| GetFirmwareType | 不存在时,调用NtQuerySystemInformation。 +| IsNativeVhdBoot | 不存在时,调用NtQuerySystemInformation。 +| RtlCaptureStackBackTrace | 调用ntdll.RtlCaptureStackBackTrace。 +| SetFileCompletionNotificationModes | 不存在时,什么也不做。 +| GetQueuedCompletionStatusEx | 不存在时,调用 GetQueuedCompletionStatus。 +| FindFirstFileEx(W/A) | Windows XP、Vista兼容 FIND_FIRST_EX_LARGE_FETCH、FindExInfoStandard参数。 +| GetProcessGroupAffinity | 不存在时,始终认为只有一组CPU。 +| QueryUnbiasedInterruptTime | 不存在时,读取KUSER_SHARED_DATA::InterruptTime值模拟UnbiasedInterruptTime。 +| FindStringOrdinal | 不存在时,调用CompareStringOrdinal。 +| GetEnabledXStateFeatures | 不存在时,调用IsProcessorFeaturePresent。 +| SetXStateFeaturesMask | 不存在时,内部实现。 +| InitializeContext | 不存在时,内部实现。 +| InitializeContext2 | 不存在时,调用InitializeContext。 +| LocateXStateFeature | 不存在时,内部实现。 +| CopyContext | 不存在时,内部实现。 +| QueryIdleProcessorCycleTimeEx | 不存在时,调用QueryIdleProcessorCycleTime。 +| QueryIdleProcessorCycleTime | 不存在时,随便返回一组数字代表当前进程空闲时间。 +| SetThreadIdealProcessorEx | 不存在时,调用SetThreadIdealProcessor。 +| GetThreadIdealProcessorEx | 不存在时,调用SetThreadIdealProcessor。 +| GetUserPreferredUILanguages | 不存在时,调用GetThreadPreferredUILanguages。 +| EnumTimeFormatsEx | 不存在时,调用EnumTimeFormatsW。 +| GetCalendarInfoEx | 不存在时,调用GetCalendarInfoW。 +| GetNLSVersionEx | 不存在时,返回一个假版本。 +| IsNLSDefinedString | 不存在时,调用GetStringTypeW。 +| FindNLSStringEx | 调用 CompareStringW。 +| SetProcessWorkingSetSizeEx | 不存在时,调用SetProcessWorkingSetSize。 +| GetProcessWorkingSetSizeEx | 不存在时,调用GetProcessWorkingSetSize。 +| GetTimeZoneInformationForYear | 不存在时,直接读取`Time Zones`注册表。 +| SetProcessDEPPolicy | 不存在时,调用NtSetInformationProcess。 +| GetSystemDEPPolicy | 不存在时,返回总是关闭。 +| DisableThreadLibraryCalls | 不存在时,始终返回成功。 +| CreateRemoteThreadEx | 不存在时,调用CreateRemoteThread。 +| WerRegisterRuntimeExceptionModule | 不存在时,返回S_OK。 +| WerUnregisterRuntimeExceptionModule | 不存在时,返回S_OK。 +| Wow64GetThreadContext | 不存在时,调用GetThreadContext或者返回ERROR_INVALID_PARAMETER。 +| SetDefaultDllDirectories | 不存在时,手工控制LoadLibrary加载顺序。 +| SetDllDirectoryW(A) | 内部保存路径,并且控制LoadLibrary加载顺序。 +| GetDllDirectoryW(A) | 获取内部保存的路径。 +| AddDllDirectory | 内部保存路径,并且控制LoadLibrary加载顺序。 +| RemoveDllDirectory | 内部移除路径。 +| GetCurrentPackageFullName | 返回 APPMODEL_ERROR_NO_PACKAGE。 +| OpenProcess | 额外处理 PROCESS_QUERY_LIMITED_INFORMATION、PROCESS_SET_LIMITED_INFORMATION。 +| GetThreadDescription | 返回空字符串。 +| SetThreadDescription | 返回 `E_NOTIMPL`。 | GetSystemFirmwareTable | 读取PhysicalMemory或者注册表。注意:目前仅支持'RSMB'、'ACPI'。 | GetPhysicallyInstalledSystemMemory | 调用GetSystemFirmwareTable。 - -## mfplat.dll -| 函数 | Fallback -| ---- | ----------- -| MFCreateDeviceSource | 不存在时,返回E_NOTIMPL。 -| MFEnumDeviceSources | 不存在时,返回E_NOTIMPL。 - -## mfplat.dll -| 函数 | Fallback -| ---- | ----------- -| MFCreateDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 -| MFCreateDXGISurfaceBuffer | 不存在时,返回E_NOTIMPL。 -| MFLockDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 -| MFUnlockDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 -| MFCreateAlignedMemoryBuffer | 不存在时,返回E_NOTIMPL。 -| MFCreateAsyncResult | 不存在时,返回E_NOTIMPL。 -| MFCreateAttributes | 不存在时,返回E_NOTIMPL。 -| MFCreateEventQueue | 不存在时,返回E_NOTIMPL。 -| MFCreateMediaBufferWrapper | 不存在时,返回E_NOTIMPL。 -| MFCreateMediaEvent | 不存在时,返回E_NOTIMPL。 -| MFCreateMediaType | 不存在时,返回E_NOTIMPL。 -| MFCreateMemoryBuffer | 不存在时,返回E_NOTIMPL。 -| MFCreatePresentationDescriptor | 不存在时,返回E_NOTIMPL。 -| MFCreateSample | 不存在时,返回E_NOTIMPL。 -| MFCreateStreamDescriptor | 不存在时,返回E_NOTIMPL。 -| MFCreateWaveFormatExFromMFMediaType | 不存在时,返回E_NOTIMPL。 -| MFFrameRateToAverageTimePerFrame | 不存在时,返回E_NOTIMPL。 -| MFGetSystemTime | 不存在时,调用GetSystemTimeAsFileTime。 -| MFInitMediaTypeFromWaveFormatEx | 不存在时,返回E_NOTIMPL。 -| MFShutdown | 不存在时,返回E_NOTIMPL。 -| MFStartup | 不存在时,返回E_NOTIMPL。 -| MFTEnumEx | 不存在时,返回E_NOTIMPL。 - -## mfreadwrite.dll -| 函数 | Fallback -| ---- | ----------- -| MFCreateSourceReaderFromMediaSource | 不存在时,返回E_NOTIMPL。 - -## ndfapi.dll -| 函数 | Fallback -| ---- | ----------- -| NdfCreateWebIncident | 不存在时,返回一个伪句柄假装成功。 -| NdfCloseIncident | 不存在时,假装成功关闭句柄。 -| NdfExecuteDiagnosis | 不存在时,假装什么问题也没有发现。 - -## netapi32.dll -| 函数 | Fallback -| ---- | ----------- -| NetGetAadJoinInformation | 不存在时,始终认为没有加入 Azure AD 帐户 账号。 -| NetFreeAadJoinInformation | 不存在时,什么也不做。 - -## ntdll.dll -| 函数 | Fallback -| ---- | ----------- -| NtCancelIoFileEx | 不存在时,调用 NtCancelIoFile。注意:将取消此文件的所有IO请求。 -| NtOpenKeyEx | 不存在时,调用 NtOpenKey 或者 NtCreateKey。 - -## ole32.dll -| 函数 | Fallback -| ---- | ----------- -| CoGetApartmentType | 不存在时,调用IComThreadingInfo。 - -## pdh.dll -| 函数 | Fallback -| ---- | ----------- -| PdhAddEnglishCounterW(A) | 不存在时,调用PdhAddCounterW(A)。 - -## powrprof.dll -| 函数 | Fallback -| ---- | ----------- -| PowerDeterminePlatformRole | 不存在时,返回PlatformRoleDesktop。 -| PowerDeterminePlatformRoleEx | 不存在时,调用PowerDeterminePlatformRole。 -| PowerRegisterSuspendResumeNotification | 不存在时,使用窗口模拟。 -| PowerUnregisterSuspendResumeNotification | 内部实现。 -| PowerGetActiveScheme | 不存在时,始终认为是平衡模式。 -| PowerReadACValue | 不存在时,读取注册表。(目前仅支持ConsoleLock) -| PowerReadDCValue | 不存在时,读取注册表。(目前仅支持ConsoleLock) - -## PropSys.dll -| 函数 | Fallback -| ---- | ----------- -| InitPropVariantFromCLSID | 不存在时,CoTaskMemAlloc分配内存。 -| PSGetPropertyKeyFromName | 不存在时,返回 TYPE_E_ELEMENTNOTFOUND(属性不存在)。 -| PSCreateMemoryPropertyStore | 不存在时,返回 E_NOTIMPL。 -| VariantCompare | 不存在时,内部实现。 - -## psapi.dll -| 函数 | Fallback -| ---- | ----------- -| EnumProcessModulesEx | 不存在时,调用EnumProcessModules。 -| GetWsChangesEx | 不存在时,调用GetWsChanges。 -| *QueryWorkingSetEx | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 - -## setupapi.dll -| 函数 | Fallback -| ---- | ----------- -| SetupDiGetDevicePropertyW | 不存在时,调用SetupDiGetDeviceRegistryPropertyW。 -| SetupDiSetDevicePropertyW | 不存在时,调用SetupDiSetDeviceRegistryPropertyW。 -| SetupDiGetClassPropertyW | 不存在时,调用SetupDiGetClassRegistryPropertyW。 -| SetupDiGetClassPropertyExW | 不存在时,调用SetupDiGetClassRegistryPropertyW。 -| SetupDiSetClassPropertyW | 不存在时,调用SetupDiSetClassRegistryPropertyW。 -| SetupDiSetClassPropertyExW | 不存在时,调用SetupDiSetClassRegistryPropertyW。 - -## shcore.dll -| 函数 | Fallback -| ---- | ----------- -| GetDpiForMonitor | 不存在时,调用GetDeviceCaps。 -| GetProcessDpiAwareness | 调用 IsProcessDPIAware。 -| SetProcessDpiAwareness | 不存在时,调用SetProcessDPIAware。 -| SetProcessDPIAware | 不存在时,直接返回 TRUE。 - -## shell32.dll -| 函数 | Fallback -| ---- | ----------- -| SHGetKnownFolderPath | 不存在时,调用SHGetFolderPathW。 -| SHSetKnownFolderPath | 不存在时,调用SHSetFolderPathW。 -| SHGetKnownFolderIDList | 不存在时,调用SHGetFolderLocation。 -| SHBindToFolderIDListParent | 不存在时,调用IShellFolder。 -| SHBindToFolderIDListParentEx | 不存在时,调用IShellFolder。 -| SHBindToObject | 不存在时,调用IShellFolder。 -| SHCreateItemFromIDList | 不存在时,调用IShellItem。 -| SHCreateItemWithParent | 不存在时,调用IShellItem。 -| SHCreateItemFromRelativeName | 不存在时,调用IShellItem。 -| SHGetNameFromIDList | 不存在时,调用IShellItem。 -| SHCreateShellItem | 不存在时,调用IShellItem。 -| SHCreateItemFromParsingName | 不存在时,调用SHParseDisplayName。 -| Shell_NotifyIconGetRect | 不存在时,调用SendMessageW(可能不适用于Vista系统)。 -| SHGetStockIconInfo | 不存在时,调用LoadImageW。 -| SHGetPropertyStoreForWindow | 不存在时,报告错误 E_NOTIMPL。 -| SHOpenWithDialog | 不存在时,报告错误 E_NOTIMPL。 - -## shlwapi.dll -| 函数 | Fallback -| ---- | ----------- -| StrToInt64ExW(A) | 不存在时,手工解析字符串。 - -## UIAutomationCore.dll -| 函数 | Fallback -| ---- | ----------- -| UiaClientsAreListening | 不存在时,假装没有人在监听。 -| UiaHostProviderFromHwnd | 不存在时,报告错误 E_NOTIMPL。 -| UiaRaiseAutomationEvent | 不存在时,报告错误 E_NOTIMPL。 -| UiaRaiseAutomationPropertyChangedEvent | 不存在时,报告错误 E_NOTIMPL。 -| UiaReturnRawElementProvider | 不存在时,报告错误 E_NOTIMPL。 -| UiaGetReservedMixedAttributeValue | 不存在时,报告错误 E_NOTIMPL。 -| UiaGetReservedNotSupportedValue | 不存在时,报告错误 E_NOTIMPL。 -| UiaRaiseStructureChangedEvent | 不存在时,报告错误 E_NOTIMPL。 -| UiaRaiseNotificationEvent | 不存在时,假装成功。 - -## user32.dll -| 函数 | Fallback -| ---- | ----------- -| IsWow64Process | 不存在时,返回TRUE,并设置 `*Wow64Process = FALSE`。 -| SetProcessDpiAwarenessContext | 不存在时,调用SetProcessDpiAwareness。 -| GetDpiForSystem | 不存在时,调用GetDeviceCaps。 -| GetDpiForWindow | 不存在时,调用GetDpiForMonitor。 -| GetSystemMetricsForDpi | 不存在时,调用GetSystemMetrics。 -| AdjustWindowRectExForDpi | 不存在时,调用AdjustWindowRectEx。 -| SystemParametersInfoW(A) | SPI_GETNONCLIENTMETRICS修正。 -| SystemParametersInfoForDpi | 不存在时,调用SystemParametersInfoW。 -| RegisterSuspendResumeNotification | 不存在时,使用窗口模拟。 -| UnregisterSuspendResumeNotification | 不存在时,内部实现。 -| IsProcessDPIAware | 不存在时,返回 FALSE。 -| SetProcessDPIAware | 不存在时,什么都不做,假装成功。 -| GetWindowDisplayAffinity | 不存在时,TRUE,并报告窗口没有任何保护`WDA_NONE`。 -| SetWindowDisplayAffinity | 不存在时,什么都不做,假装成功。 -| RegisterTouchWindow | 不存在时,什么都不做,假装成功。 -| UnregisterTouchWindow | 不存在时,什么都不做,假装成功。 -| IsTouchWindow | 不存在时,始终报告非触摸窗口。 -| GetTouchInputInfo | 不存在时,报告错误 ERROR_INVALID_HANDLE。 -| CloseTouchInputHandle | 不存在时,报告错误 ERROR_INVALID_HANDLE。 -| *ChangeWindowMessageFilterEx | 不存在时,调用ChangeWindowMessageFilter。温馨提示:将影响该进程的所有窗口。 -| ChangeWindowMessageFilter | 不存在时,什么都不做,假装成功。 -| UpdateLayeredWindowIndirect | 不存在时,调用UpdateLayeredWindow。 -| AddClipboardFormatListener | 不存在时,什么都不做,假装成功。 -| RemoveClipboardFormatListener | 不存在时,什么都不做,假装成功。 -| RegisterPowerSettingNotification | 不存在时,什么都不做,假装成功。 -| UnregisterPowerSettingNotification | 不存在时,什么都不做,假装成功。 -| DisplayConfigGetDeviceInfo | 不存在时,报告没有安装驱动。 -| GetDisplayConfigBufferSizes | 不存在时,报告没有安装驱动。 -| QueryDisplayConfig | 不存在时,报告没有安装驱动。 -| RegisterPointerDeviceNotifications | 不存在时,假装成功。 -| GetPointerDevices | 不存在时,假装没有触摸设备。 -| GetPointerDevice | 不存在时,假装没有触摸设备。 -| GetPointerPenInfo | 不存在时,假装没有触摸设备。 -| GetPointerType | 不存在时,假装没有触摸设备。 -| InitializeTouchInjection | 报告错误 ERROR_INVALID_PARAMETER。 -| InjectTouchInput | 报告错误 ERROR_INVALID_PARAMETER。 -| GetAwarenessFromDpiAwarenessContext | 内部实现。 -| AreDpiAwarenessContextsEqual | 内部实现。 -| EnableNonClientDpiScaling | 假装成功。 -| GetPointerFrameTouchInfo | 报告错误 ERROR_INVALID_PARAMETER。 -| GetPointerFrameTouchInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 -| GetPointerInfo | 报告错误 ERROR_INVALID_PARAMETER。 -| GetPointerPenInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 -| SkipPointerFrameMessages | 假装成功。 -| GetThreadDpiAwarenessContext | 调用 GetProcessDpiAwareness。 -| GetWindowDpiAwarenessContext | 调用 GetProcessDpiAwareness。 -| GetDisplayAutoRotationPreferences | 返回 ORIENTATION_PREFERENCE_NONE。 -| SetDisplayAutoRotationPreferences | 假装成功。 -| GetPointerInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 -| GetPointerTouchInfo | 报告错误 ERROR_INVALID_PARAMETER。 -| GetPointerTouchInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 -| IsMouseInPointerEnabled | 返回关闭。 -| EnableMouseInPointer | 假装处于关闭状态。 -| GetPointerDeviceRects | 报告错误 ERROR_INVALID_PARAMETER。 - -## userenv.dll -| 函数 | Fallback -| ---- | ----------- -| CreateAppContainerProfile | 不存在时,返回E_NOTIMPL。 -| DeleteAppContainerProfile | 不存在时,返回E_NOTIMPL。 -| DeriveAppContainerSidFromAppContainerName | 不存在时,返回E_NOTIMPL。 -| GetAppContainerFolderPath | 不存在时,返回E_NOTIMPL。 -| GetAppContainerRegistryLocation | 不存在时,返回E_NOTIMPL。 - -## uxtheme.dll -| 函数 | Fallback -| ---- | ----------- -| DrawThemeTextEx | 不存在时,尝试获取非导出DrawThemeTextEx。如果任然获取失败则调用DrawThemeText。 -| GetThemeTransitionDuration | 不存在时,返回E_NOTIMPL。 -| SetWindowThemeAttribute | 不存在时,返回E_NOTIMPL。 - -## version.dll -| 函数 | Fallback -| ---- | ----------- -| GetFileVersionInfoExW(A) | 不存在时,调用GetFileVersionInfoW(A)。 -| GetFileVersionInfoSizeExW(A) | 不存在时,调用GetFileVersionInfoSizeW(A)。 - -## wevtapi.dll -| 函数 | Fallback -| ---- | ----------- -| EvtClose | 不存在时,返回TRUE。 -| EvtCreateRenderContext | 不存在时,报告ERROR_NOT_SUPPORTED。 -| EvtNext | 不存在时,报告ERROR_NOT_SUPPORTED。 -| EvtQuery | 不存在时,报告ERROR_NOT_SUPPORTED。 -| EvtRender | 不存在时,报告ERROR_NOT_SUPPORTED。 - -## WinHttp.dll -| 函数 | Fallback -| ---- | ----------- -| WinHttpCreateProxyResolver | 不存在时,内部实现。 -| WinHttpGetProxyForUrlEx | 不存在时,异步调用WinHttpGetProxyForUrl。 -| WinHttpGetProxyResult | 不存在时,内部实现。 -| WinHttpFreeProxyResult | 不存在时,内部实现。 - -## WinUsb.dll -| 函数 | Fallback -| ---- | ----------- -| WinUsb_Free | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_GetAssociatedInterface | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_GetOverlappedResult | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_Initialize | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_ReadPipe | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_ResetPipe | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_SetCurrentAlternateSetting | 不存在时,报告ERROR_INVALID_HANDLE。 -| WinUsb_WritePipe | 不存在时,报告ERROR_INVALID_HANDLE。 - -## ws2_32.dll -| 函数 | Fallback -| ---- | ----------- -| InetPtonW(inet_pton) | 不存在时,类似于sscanf手工分析字符串。 -| InetNtopW(inet_ntop) | 不存在时,类似于sprintf手工生成字符串。 -| WSAPoll | 不存在时,调用select。 -| GetAddrInfoExCancel | 不存在时,使用线程模拟。 -| GetAddrInfoExW(A) | 不存在时,调用GetAddrInfoW(A)。 -| GetAddrInfoExOverlappedResult | 不存在时,内部实现。 -| FreeAddrInfoEx(W) | 不存在时,内部实现。 -| GetAddrInfoW | 不存在时,调用getaddrinfo。 -| FreeAddrInfoW | 不存在时,内部实现。 -| WSASocketW(A) | 低于6.1.7601时自动去除 `WSA_FLAG_NO_HANDLE_INHERIT`。 -| WSAIoctl | 低于6.0时,`SIO_BASE_HANDLE` 代码返回SOCKET自身。 + +## mfplat.dll +| 函数 | Fallback +| ---- | ----------- +| MFCreateDeviceSource | 不存在时,返回E_NOTIMPL。 +| MFEnumDeviceSources | 不存在时,返回E_NOTIMPL。 + +## mfplat.dll +| 函数 | Fallback +| ---- | ----------- +| MFCreateDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 +| MFCreateDXGISurfaceBuffer | 不存在时,返回E_NOTIMPL。 +| MFLockDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 +| MFUnlockDXGIDeviceManager | 不存在时,返回E_NOTIMPL。 +| MFCreateAlignedMemoryBuffer | 不存在时,返回E_NOTIMPL。 +| MFCreateAsyncResult | 不存在时,返回E_NOTIMPL。 +| MFCreateAttributes | 不存在时,返回E_NOTIMPL。 +| MFCreateEventQueue | 不存在时,返回E_NOTIMPL。 +| MFCreateMediaBufferWrapper | 不存在时,返回E_NOTIMPL。 +| MFCreateMediaEvent | 不存在时,返回E_NOTIMPL。 +| MFCreateMediaType | 不存在时,返回E_NOTIMPL。 +| MFCreateMemoryBuffer | 不存在时,返回E_NOTIMPL。 +| MFCreatePresentationDescriptor | 不存在时,返回E_NOTIMPL。 +| MFCreateSample | 不存在时,返回E_NOTIMPL。 +| MFCreateStreamDescriptor | 不存在时,返回E_NOTIMPL。 +| MFCreateWaveFormatExFromMFMediaType | 不存在时,返回E_NOTIMPL。 +| MFFrameRateToAverageTimePerFrame | 不存在时,返回E_NOTIMPL。 +| MFGetSystemTime | 不存在时,调用GetSystemTimeAsFileTime。 +| MFInitMediaTypeFromWaveFormatEx | 不存在时,返回E_NOTIMPL。 +| MFShutdown | 不存在时,返回E_NOTIMPL。 +| MFStartup | 不存在时,返回E_NOTIMPL。 +| MFTEnumEx | 不存在时,返回E_NOTIMPL。 + +## mfreadwrite.dll +| 函数 | Fallback +| ---- | ----------- +| MFCreateSourceReaderFromMediaSource | 不存在时,返回E_NOTIMPL。 + +## ndfapi.dll +| 函数 | Fallback +| ---- | ----------- +| NdfCreateWebIncident | 不存在时,返回一个伪句柄假装成功。 +| NdfCloseIncident | 不存在时,假装成功关闭句柄。 +| NdfExecuteDiagnosis | 不存在时,假装什么问题也没有发现。 + +## netapi32.dll +| 函数 | Fallback +| ---- | ----------- +| NetGetAadJoinInformation | 不存在时,始终认为没有加入 Azure AD 帐户 账号。 +| NetFreeAadJoinInformation | 不存在时,什么也不做。 + +## ntdll.dll +| 函数 | Fallback +| ---- | ----------- +| NtCancelIoFileEx | 不存在时,调用 NtCancelIoFile。注意:将取消此文件的所有IO请求。 +| NtOpenKeyEx | 不存在时,调用 NtOpenKey 或者 NtCreateKey。 + +## ole32.dll +| 函数 | Fallback +| ---- | ----------- +| CoGetApartmentType | 不存在时,调用IComThreadingInfo。 + +## pdh.dll +| 函数 | Fallback +| ---- | ----------- +| PdhAddEnglishCounterW(A) | 不存在时,调用PdhAddCounterW(A)。 + +## powrprof.dll +| 函数 | Fallback +| ---- | ----------- +| PowerDeterminePlatformRole | 不存在时,返回PlatformRoleDesktop。 +| PowerDeterminePlatformRoleEx | 不存在时,调用PowerDeterminePlatformRole。 +| PowerRegisterSuspendResumeNotification | 不存在时,使用窗口模拟。 +| PowerUnregisterSuspendResumeNotification | 内部实现。 +| PowerGetActiveScheme | 不存在时,始终认为是平衡模式。 +| PowerReadACValue | 不存在时,读取注册表。(目前仅支持ConsoleLock) +| PowerReadDCValue | 不存在时,读取注册表。(目前仅支持ConsoleLock) + +## PropSys.dll +| 函数 | Fallback +| ---- | ----------- +| InitPropVariantFromCLSID | 不存在时,CoTaskMemAlloc分配内存。 +| PSGetPropertyKeyFromName | 不存在时,返回 TYPE_E_ELEMENTNOTFOUND(属性不存在)。 +| PSCreateMemoryPropertyStore | 不存在时,返回 E_NOTIMPL。 +| VariantCompare | 不存在时,内部实现。 + +## psapi.dll +| 函数 | Fallback +| ---- | ----------- +| EnumProcessModulesEx | 不存在时,调用EnumProcessModules。 +| GetWsChangesEx | 不存在时,调用GetWsChanges。 +| *QueryWorkingSetEx | 不存在时,返回FALSE,并设置 LastError = ERROR_INVALID_FUNCTION。 + +## setupapi.dll +| 函数 | Fallback +| ---- | ----------- +| SetupDiGetDevicePropertyW | 不存在时,调用SetupDiGetDeviceRegistryPropertyW。 +| SetupDiSetDevicePropertyW | 不存在时,调用SetupDiSetDeviceRegistryPropertyW。 +| SetupDiGetClassPropertyW | 不存在时,调用SetupDiGetClassRegistryPropertyW。 +| SetupDiGetClassPropertyExW | 不存在时,调用SetupDiGetClassRegistryPropertyW。 +| SetupDiSetClassPropertyW | 不存在时,调用SetupDiSetClassRegistryPropertyW。 +| SetupDiSetClassPropertyExW | 不存在时,调用SetupDiSetClassRegistryPropertyW。 + +## shcore.dll +| 函数 | Fallback +| ---- | ----------- +| GetDpiForMonitor | 不存在时,调用GetDeviceCaps。 +| GetProcessDpiAwareness | 调用 IsProcessDPIAware。 +| SetProcessDpiAwareness | 不存在时,调用SetProcessDPIAware。 +| SetProcessDPIAware | 不存在时,直接返回 TRUE。 + +## shell32.dll +| 函数 | Fallback +| ---- | ----------- +| SHGetKnownFolderPath | 不存在时,调用SHGetFolderPathW。 +| SHSetKnownFolderPath | 不存在时,调用SHSetFolderPathW。 +| SHGetKnownFolderIDList | 不存在时,调用SHGetFolderLocation。 +| SHBindToFolderIDListParent | 不存在时,调用IShellFolder。 +| SHBindToFolderIDListParentEx | 不存在时,调用IShellFolder。 +| SHBindToObject | 不存在时,调用IShellFolder。 +| SHCreateItemFromIDList | 不存在时,调用IShellItem。 +| SHCreateItemWithParent | 不存在时,调用IShellItem。 +| SHCreateItemFromRelativeName | 不存在时,调用IShellItem。 +| SHGetNameFromIDList | 不存在时,调用IShellItem。 +| SHCreateShellItem | 不存在时,调用IShellItem。 +| SHCreateItemFromParsingName | 不存在时,调用SHParseDisplayName。 +| Shell_NotifyIconGetRect | 不存在时,调用SendMessageW(可能不适用于Vista系统)。 +| SHGetStockIconInfo | 不存在时,调用LoadImageW。 +| SHGetPropertyStoreForWindow | 不存在时,报告错误 E_NOTIMPL。 +| SHOpenWithDialog | 不存在时,报告错误 E_NOTIMPL。 + +## shlwapi.dll +| 函数 | Fallback +| ---- | ----------- +| StrToInt64ExW(A) | 不存在时,手工解析字符串。 + +## UIAutomationCore.dll +| 函数 | Fallback +| ---- | ----------- +| UiaClientsAreListening | 不存在时,假装没有人在监听。 +| UiaHostProviderFromHwnd | 不存在时,报告错误 E_NOTIMPL。 +| UiaRaiseAutomationEvent | 不存在时,报告错误 E_NOTIMPL。 +| UiaRaiseAutomationPropertyChangedEvent | 不存在时,报告错误 E_NOTIMPL。 +| UiaReturnRawElementProvider | 不存在时,报告错误 E_NOTIMPL。 +| UiaGetReservedMixedAttributeValue | 不存在时,报告错误 E_NOTIMPL。 +| UiaGetReservedNotSupportedValue | 不存在时,报告错误 E_NOTIMPL。 +| UiaRaiseStructureChangedEvent | 不存在时,报告错误 E_NOTIMPL。 +| UiaRaiseNotificationEvent | 不存在时,假装成功。 + +## user32.dll +| 函数 | Fallback +| ---- | ----------- +| IsWow64Process | 不存在时,返回TRUE,并设置 `*Wow64Process = FALSE`。 +| SetProcessDpiAwarenessContext | 不存在时,调用SetProcessDpiAwareness。 +| GetDpiForSystem | 不存在时,调用GetDeviceCaps。 +| GetDpiForWindow | 不存在时,调用GetDpiForMonitor。 +| GetSystemMetricsForDpi | 不存在时,调用GetSystemMetrics。 +| AdjustWindowRectExForDpi | 不存在时,调用AdjustWindowRectEx。 +| SystemParametersInfoW(A) | SPI_GETNONCLIENTMETRICS修正。 +| SystemParametersInfoForDpi | 不存在时,调用SystemParametersInfoW。 +| RegisterSuspendResumeNotification | 不存在时,使用窗口模拟。 +| UnregisterSuspendResumeNotification | 不存在时,内部实现。 +| IsProcessDPIAware | 不存在时,返回 FALSE。 +| SetProcessDPIAware | 不存在时,什么都不做,假装成功。 +| GetWindowDisplayAffinity | 不存在时,TRUE,并报告窗口没有任何保护`WDA_NONE`。 +| SetWindowDisplayAffinity | 不存在时,什么都不做,假装成功。 +| RegisterTouchWindow | 不存在时,什么都不做,假装成功。 +| UnregisterTouchWindow | 不存在时,什么都不做,假装成功。 +| IsTouchWindow | 不存在时,始终报告非触摸窗口。 +| GetTouchInputInfo | 不存在时,报告错误 ERROR_INVALID_HANDLE。 +| CloseTouchInputHandle | 不存在时,报告错误 ERROR_INVALID_HANDLE。 +| *ChangeWindowMessageFilterEx | 不存在时,调用ChangeWindowMessageFilter。温馨提示:将影响该进程的所有窗口。 +| ChangeWindowMessageFilter | 不存在时,什么都不做,假装成功。 +| UpdateLayeredWindowIndirect | 不存在时,调用UpdateLayeredWindow。 +| AddClipboardFormatListener | 不存在时,什么都不做,假装成功。 +| RemoveClipboardFormatListener | 不存在时,什么都不做,假装成功。 +| RegisterPowerSettingNotification | 不存在时,什么都不做,假装成功。 +| UnregisterPowerSettingNotification | 不存在时,什么都不做,假装成功。 +| DisplayConfigGetDeviceInfo | 不存在时,报告没有安装驱动。 +| GetDisplayConfigBufferSizes | 不存在时,报告没有安装驱动。 +| QueryDisplayConfig | 不存在时,报告没有安装驱动。 +| RegisterPointerDeviceNotifications | 不存在时,假装成功。 +| GetPointerDevices | 不存在时,假装没有触摸设备。 +| GetPointerDevice | 不存在时,假装没有触摸设备。 +| GetPointerPenInfo | 不存在时,假装没有触摸设备。 +| GetPointerType | 不存在时,假装没有触摸设备。 +| InitializeTouchInjection | 报告错误 ERROR_INVALID_PARAMETER。 +| InjectTouchInput | 报告错误 ERROR_INVALID_PARAMETER。 +| GetAwarenessFromDpiAwarenessContext | 内部实现。 +| AreDpiAwarenessContextsEqual | 内部实现。 +| EnableNonClientDpiScaling | 假装成功。 +| GetPointerFrameTouchInfo | 报告错误 ERROR_INVALID_PARAMETER。 +| GetPointerFrameTouchInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 +| GetPointerInfo | 报告错误 ERROR_INVALID_PARAMETER。 +| GetPointerPenInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 +| SkipPointerFrameMessages | 假装成功。 +| GetThreadDpiAwarenessContext | 调用 GetProcessDpiAwareness。 +| GetWindowDpiAwarenessContext | 调用 GetProcessDpiAwareness。 +| GetDisplayAutoRotationPreferences | 返回 ORIENTATION_PREFERENCE_NONE。 +| SetDisplayAutoRotationPreferences | 假装成功。 +| GetPointerInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 +| GetPointerTouchInfo | 报告错误 ERROR_INVALID_PARAMETER。 +| GetPointerTouchInfoHistory | 报告错误 ERROR_INVALID_PARAMETER。 +| IsMouseInPointerEnabled | 返回关闭。 +| EnableMouseInPointer | 假装处于关闭状态。 +| GetPointerDeviceRects | 报告错误 ERROR_INVALID_PARAMETER。 + +## userenv.dll +| 函数 | Fallback +| ---- | ----------- +| CreateAppContainerProfile | 不存在时,返回E_NOTIMPL。 +| DeleteAppContainerProfile | 不存在时,返回E_NOTIMPL。 +| DeriveAppContainerSidFromAppContainerName | 不存在时,返回E_NOTIMPL。 +| GetAppContainerFolderPath | 不存在时,返回E_NOTIMPL。 +| GetAppContainerRegistryLocation | 不存在时,返回E_NOTIMPL。 + +## uxtheme.dll +| 函数 | Fallback +| ---- | ----------- +| DrawThemeTextEx | 不存在时,尝试获取非导出DrawThemeTextEx。如果任然获取失败则调用DrawThemeText。 +| GetThemeTransitionDuration | 不存在时,返回E_NOTIMPL。 +| SetWindowThemeAttribute | 不存在时,返回E_NOTIMPL。 + +## version.dll +| 函数 | Fallback +| ---- | ----------- +| GetFileVersionInfoExW(A) | 不存在时,调用GetFileVersionInfoW(A)。 +| GetFileVersionInfoSizeExW(A) | 不存在时,调用GetFileVersionInfoSizeW(A)。 + +## wevtapi.dll +| 函数 | Fallback +| ---- | ----------- +| EvtClose | 不存在时,返回TRUE。 +| EvtCreateRenderContext | 不存在时,报告ERROR_NOT_SUPPORTED。 +| EvtNext | 不存在时,报告ERROR_NOT_SUPPORTED。 +| EvtQuery | 不存在时,报告ERROR_NOT_SUPPORTED。 +| EvtRender | 不存在时,报告ERROR_NOT_SUPPORTED。 + +## WinHttp.dll +| 函数 | Fallback +| ---- | ----------- +| WinHttpCreateProxyResolver | 不存在时,内部实现。 +| WinHttpGetProxyForUrlEx | 不存在时,异步调用WinHttpGetProxyForUrl。 +| WinHttpGetProxyResult | 不存在时,内部实现。 +| WinHttpFreeProxyResult | 不存在时,内部实现。 + +## WinUsb.dll +| 函数 | Fallback +| ---- | ----------- +| WinUsb_Free | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_GetAssociatedInterface | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_GetOverlappedResult | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_Initialize | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_ReadPipe | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_ResetPipe | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_SetCurrentAlternateSetting | 不存在时,报告ERROR_INVALID_HANDLE。 +| WinUsb_WritePipe | 不存在时,报告ERROR_INVALID_HANDLE。 + +## ws2_32.dll +| 函数 | Fallback +| ---- | ----------- +| InetPtonW(inet_pton) | 不存在时,类似于sscanf手工分析字符串。 +| InetNtopW(inet_ntop) | 不存在时,类似于sprintf手工生成字符串。 +| WSAPoll | 不存在时,调用select。 +| GetAddrInfoExCancel | 不存在时,使用线程模拟。 +| GetAddrInfoExW(A) | 不存在时,调用GetAddrInfoW(A)。 +| GetAddrInfoExOverlappedResult | 不存在时,内部实现。 +| FreeAddrInfoEx(W) | 不存在时,内部实现。 +| GetAddrInfoW | 不存在时,调用getaddrinfo。 +| FreeAddrInfoW | 不存在时,内部实现。 +| WSASocketW(A) | 低于6.1.7601时自动去除 `WSA_FLAG_NO_HANDLE_INHERIT`。 +| WSAIoctl | 低于6.0时,`SIO_BASE_HANDLE` 代码返回SOCKET自身。 diff --git a/src/Shared/List.h b/src/Shared/List.h new file mode 100644 index 0000000..edd18d7 --- /dev/null +++ b/src/Shared/List.h @@ -0,0 +1,68 @@ +#pragma once + +namespace YY::Thunks +{ + namespace + { + template + struct ListEntryImpl + { + ListEntry* pPrior = nullptr; + ListEntry* pNext = nullptr; + }; + + template + class ListImpl + { + public: + ListEntry* pFirst = nullptr; + ListEntry* pLast = nullptr; + + void __fastcall PushBack(ListEntry* _pItem) noexcept + { + if (!_pItem) + return; + + _pItem->pNext = nullptr; + _pItem->pPrior = pLast; + pLast = _pItem; + + if (!pFirst) + pFirst = _pItem; + } + + bool __fastcall Remove(ListEntry* _pItem) noexcept + { + if (!_pItem) + return false; + + if (!pFirst) + return false; + + auto _pPrior = _pItem->pPrior; + auto _pNext = _pItem->pNext; + if (_pPrior) + { + _pPrior->pNext = _pNext; + } + + if (_pNext) + { + _pNext->pPrior = _pPrior; + } + + if (pFirst == _pItem) + { + pFirst = _pNext; + } + + if (pLast == _pItem) + { + pLast = _pPrior; + } + + return true; + } + }; + } +} diff --git a/src/Thunks/YY_Thunks.cpp b/src/Thunks/YY_Thunks.cpp index 92042cb..e7cbf68 100644 --- a/src/Thunks/YY_Thunks.cpp +++ b/src/Thunks/YY_Thunks.cpp @@ -1,1297 +1,1541 @@ -/* -YY-Thunks支持的控制宏: -1. __FALLBACK_PREFIX:编译Lib库模式使用的API前缀修饰。一般来说只能为空或者传递 "YY_Thunks_"。 -2. __USING_NTDLL_LIB:假定构建环境存在ntdll.lib,这可以减少一些NTDLL相关函数的动态加载。 - -特殊支持的变通方案: -1. __ENABLE_WORKAROUND_ALL -启用所有兼容方案,即__ENABLE_WORKAROUND_1 ~ __ENABLE_WORKAROUND_N,全部开启。 - -2. __ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng -兼容方案1:让GetProcAddress也能取到ProcessPrng函数地址。某些代码可能强制依赖ProcessPrng。 - -3. __ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL -兼容方案2:Windows 8.1以前的版本对于匿名对象无法生效DACL。就会导致Chrome的CheckPlatformHandlePermissionsCorrespondToMode判断不准确。 -修复方案通过给匿名对象创建一个名字解决该问题。 - -特定项目的兼容方案: -1. __APPLY_CHROMIUM_WORKAROUNDS -开启Chrome项目的兼容能力,等效于同时指定__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng、__ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL。 - -*/ - -// 忽略非标准的 0 数组警告。 -#pragma warning(disable:4200) -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#define _YY_APPLY_TO_LATE_BOUND_MODULES(_APPLY) \ - _APPLY(ntdll, "ntdll" , USING_GET_MODULE_HANDLE ) \ - _APPLY(kernel32, "kernel32" , USING_GET_MODULE_HANDLE ) \ - _APPLY(kernelbase, "kernelbase" , USING_GET_MODULE_HANDLE ) \ - _APPLY(cfgmgr32, "cfgmgr32" , 0 ) \ - _APPLY(crypt32, "crypt32" , 0 ) \ - _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 ) \ - _APPLY(dxva2, "dxva2" , 0 ) \ - _APPLY(esent, "esent" , 0 ) \ - _APPLY(uxtheme, "uxtheme" , 0 ) \ - _APPLY(uiautomationcore, "uiautomationcore" , 0 ) \ - _APPLY(psapi, "psapi" , 0 ) \ - _APPLY(pdh, "pdh" , 0 ) \ - _APPLY(version, "version" , 0 ) \ - _APPLY(advapi32, "advapi32" , 0 ) \ - _APPLY(bcrypt, "bcrypt" , 0 ) \ - _APPLY(bcryptprimitives, "bcryptprimitives" , 0 ) \ - _APPLY(user32, "user32" , 0 ) \ - _APPLY(ws2_32, "ws2_32" , 0 ) \ - _APPLY(shell32, "shell32" , 0 ) \ - _APPLY(shcore, "shcore" , 0 ) \ - _APPLY(shlwapi, "shlwapi" , 0 ) \ - _APPLY(setupapi, "setupapi" , 0 ) \ - _APPLY(ole32, "ole32" , 0 ) \ - _APPLY(iphlpapi, "iphlpapi" , 0 ) \ - _APPLY(userenv, "userenv" , 0 ) \ - _APPLY(mf, "mf" , 0 ) \ - _APPLY(mfplat, "mfplat" , 0 ) \ - _APPLY(mfreadwrite, "mfreadwrite" , 0 ) \ - _APPLY(ndfapi, "ndfapi" , 0 ) \ - _APPLY(bluetoothapis, "bluetoothapis" , 0 ) \ - _APPLY(netapi32, "netapi32" , 0 ) \ - _APPLY(powrprof, "powrprof" , 0 ) \ - _APPLY(propsys, "propsys" , 0 ) \ - _APPLY(wevtapi, "wevtapi" , 0 ) \ - _APPLY(winhttp, "winhttp" , 0 ) \ - _APPLY(winusb, "winusb" , 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 ) \ - _APPLY(api_ms_win_core_winrt_error_l1_1_0, "api-ms-win-core-winrt-error-l1-1-0" , 0 ) \ - _APPLY(api_ms_win_core_path_l1_1_0, "api-ms-win-core-path-l1-1-0" , 0 ) \ - _APPLY(api_ms_win_core_synch_l1_2_0, "api-ms-win-core-synch-l1-2-0" , 0 ) - - -//全局可能使用到的函数 -#define _YY_APPLY_TO_LATE_BOUND_FUNCTIONS(_APPLY) \ - _APPLY(NtOpenSection, ntdll ) \ - _APPLY(NtCreateFile, ntdll ) \ - _APPLY(NtClose, ntdll ) \ - _APPLY(NtQueryDirectoryFile, ntdll ) \ - _APPLY(NtQueryInformationFile, ntdll ) \ - _APPLY(NtQuerySystemInformation, ntdll ) \ - _APPLY(NtSetInformationFile, ntdll ) \ - _APPLY(RtlNtStatusToDosError, ntdll ) \ - _APPLY(RtlDetermineDosPathNameType_U, ntdll ) \ - _APPLY(RtlDosPathNameToNtPathName_U, ntdll ) \ - _APPLY(RtlDosPathNameToNtPathName_U_WithStatus, ntdll ) \ - _APPLY(RtlFreeUnicodeString, ntdll ) \ - _APPLY(NtQueryObject, ntdll ) \ - _APPLY(NtQueryInformationThread, ntdll ) \ - _APPLY(NtSetInformationThread, ntdll ) \ - _APPLY(NtQueryInformationProcess, ntdll ) \ - _APPLY(NtSetInformationProcess, ntdll ) \ - _APPLY(NtDeleteKey, ntdll ) \ - _APPLY(NtCreateKey, ntdll ) \ - _APPLY(NtOpenKey, ntdll ) \ - _APPLY(NtOpenKeyedEvent, ntdll ) \ - _APPLY(NtWaitForKeyedEvent, ntdll ) \ - _APPLY(NtReleaseKeyedEvent, ntdll ) \ - _APPLY(RtlAdjustPrivilege, ntdll ) \ - _APPLY(RtlPcToFileHeader, ntdll ) \ - _APPLY(LdrAddRefDll, ntdll ) \ - _APPLY(RtlWow64EnableFsRedirectionEx, ntdll ) \ - _APPLY(LdrLoadDll, ntdll ) \ - _APPLY(RtlDllShutdownInProgress, ntdll ) \ - _APPLY(RtlCutoverTimeToSystemTime, ntdll ) \ - _APPLY(NtCancelIoFile, ntdll ) \ - _APPLY(NtWow64ReadVirtualMemory64, ntdll ) \ - _APPLY(RtlValidSid, ntdll ) \ - _APPLY(RtlValidAcl, ntdll ) \ - _APPLY(RtlFirstFreeAce, ntdll ) \ - _APPLY(RtlCopySid, ntdll ) \ - _APPLY(AddDllDirectory, kernel32 ) \ - _APPLY(SystemFunction036, advapi32 ) - - -#include -#include - -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#endif - -#define _WINSOCKAPI_ -#define PSAPI_VERSION 1 - -#if (YY_Thunks_Target < __WindowsNT6) -#define INITKNOWNFOLDERS -#endif - -#ifndef __WarningMessage__ -#define STRING2(x) #x -#define STRING(x) STRING2(x) -#define __WarningMessage__(msg) __pragma(message (__FILE__ "(" STRING(__LINE__) "): warning Thunks: " # msg)) -#endif - -#if !defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (defined(__ENABLE_WORKAROUND_ALL) || defined(__APPLY_CHROMIUM_WORKAROUNDS)) -#define __ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng 1 -#endif - -#if !defined(__ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL) && (defined(__ENABLE_WORKAROUND_ALL) || defined(__APPLY_CHROMIUM_WORKAROUNDS)) -#define __ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL 1 -#endif - -#ifndef __FALLBACK_PREFIX -#define __FALLBACK_PREFIX -#define __YY_Thunks_libs 0 -#else -#define __YY_Thunks_libs 1 -#endif - -#if !defined(__USING_NTDLL_LIB) && (__YY_Thunks_libs || YY_Thunks_Target >= __WindowsNT10_10240) -// lib模式下必然存在 ntdll.lib,此外最小支持Windows 10时,我们因为强制依赖Windows 10 SDK,所以也必然存在ntdll.lib。 -#define __USING_NTDLL_LIB 1 -#endif - -#define _Disallow_YY_KM_Namespace -#include "km.h" -#include -#include -#include -#include -#include - -#include - -EXTERN_C -BOOLEAN -__stdcall -SystemFunction036( - _Out_writes_bytes_(RandomBufferLength) PVOID RandomBuffer, - _In_ ULONG RandomBufferLength - ); - -EXTERN_C -BOOLEAN -__stdcall -RtlCutoverTimeToSystemTime( - PTIME_FIELDS CutoverTime, - PLARGE_INTEGER SystemTime, - PLARGE_INTEGER CurrentSystemTime, - BOOLEAN ThisYear - ); - -#include "YY_Thunks.h" - -#if (YY_Thunks_Target < __WindowsNT5_2_SP1) && !defined(__Comment_Lib_advapi32) -#define __Comment_Lib_advapi32 -#pragma comment(lib, "Advapi32.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_shlwapi) -#define __Comment_Lib_shlwapi -#pragma comment(lib, "Shlwapi.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_ws2_32) -#define __Comment_Lib_ws2_32 -#pragma comment(lib, "Ws2_32.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_version) -#define __Comment_Lib_version -#pragma comment(lib, "version.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_ole32) -#define __Comment_Lib_ole32 -#pragma comment(lib, "ole32.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_shell32) -#define __Comment_Lib_shell32 -#pragma comment(lib, "shell32.lib") -#endif - -// PSAPI2Kernel32.def -#if (YY_Thunks_Target < __WindowsNT6_1) && !defined(__Comment_Lib_psapi) -#define __Comment_Lib_psapi -#pragma comment(lib, "psapi.lib") -#endif - -#if (YY_Thunks_Target >= __WindowsNT6_3) && !defined(__Comment_Lib_shcore) -#define __Comment_Lib_shcore -#pragma comment(lib, "Shcore.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT6_3) && !defined(__Comment_Lib_gdi32) -#define __Comment_Lib_gdi32 -#pragma comment(lib, "Gdi32.lib") -#endif - -#if (YY_Thunks_Target < __WindowsNT10_10240) && !defined(__Comment_Lib_user32) -#define __Comment_Lib_user32 -#pragma comment(lib, "User32.lib") -#endif - -#if defined(__USING_NTDLL_LIB) -#pragma comment(lib, "ntdll.lib") -#endif - -#include - -//展开函数的所有的 声明 以及 try_get_ 函数 -#define __DEFINE_THUNK_EXTERN_PREFIX(_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ - __APPLY_UNIT_TEST_BOOL(_FUNCTION); \ - EXTERN_C _RETURN_ _CONVENTION_ _CRT_CONCATENATE_(_PREFIX, _FUNCTION)(__VA_ARGS__); \ - static decltype(_CRT_CONCATENATE_(_PREFIX, _FUNCTION))* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept; \ - __if_not_exists(_CRT_CONCATENATE(try_get_, _FUNCTION)) - -#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) __DEFINE_THUNK_EXTERN_PREFIX(__FALLBACK_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, __VA_ARGS__) - -#include "Thunks\YY_Thunks_List.hpp" - -#undef __DEFINE_THUNK - -namespace YY::Thunks::internal -{ - namespace - { - inline UINT8 __fastcall BitsCount(ULONG32 _fBitMask) - { -#if defined(_M_IX86) || defined(_M_AMD64) - return static_cast(__popcnt(_fBitMask)); -#else - _fBitMask = (_fBitMask & 0x55555555) + ((_fBitMask >> 1) & 0x55555555); - _fBitMask = (_fBitMask & 0x33333333) + ((_fBitMask >> 2) & 0x33333333); - _fBitMask = (_fBitMask & 0x0f0f0f0f) + ((_fBitMask >> 4) & 0x0f0f0f0f); - _fBitMask = (_fBitMask & 0x00ff00ff) + ((_fBitMask >> 8) & 0x00ff00ff); - _fBitMask = (_fBitMask & 0x0000ffff) + ((_fBitMask >> 16) & 0x0000ffff); - return static_cast(_fBitMask); -#endif - } - - inline UINT8 __fastcall BitsCount(ULONG64 _fBitMask) - { -#if defined(_M_IX86) - return static_cast(__popcnt(static_cast(_fBitMask)) + __popcnt(static_cast(_fBitMask >> 32))); -#elif defined(_M_AMD64) - return static_cast(__popcnt64(_fBitMask)); -#else - _fBitMask = (_fBitMask & 0x55555555'55555555) + ((_fBitMask >> 1) & 0x55555555'55555555); - _fBitMask = (_fBitMask & 0x33333333'33333333) + ((_fBitMask >> 2) & 0x33333333'33333333); - _fBitMask = (_fBitMask & 0x0f0f0f0f'0f0f0f0f) + ((_fBitMask >> 4) & 0x0f0f0f0f'0f0f0f0f); - _fBitMask = (_fBitMask & 0x00ff00ff'00ff00ff) + ((_fBitMask >> 8) & 0x00ff00ff'00ff00ff); - _fBitMask = (_fBitMask & 0x0000ffff'0000ffff) + ((_fBitMask >> 16) & 0x0000ffff'0000ffff); - _fBitMask = (_fBitMask & 0x00000000'ffffffff) + ((_fBitMask >> 32) & 0x00000000'ffffffff); - return static_cast(_fBitMask); -#endif - } - - __forceinline constexpr uint64_t __fastcall MakeVersion(_In_ uint16_t _uMajor, _In_ uint16_t _uMinor, uint16_t _uBuild = 0, UINT16 _uRevision = 0) - { - uint64_t _uVersion = uint64_t(_uMajor) << 48; - _uVersion |= uint64_t(_uMinor) << 32; - _uVersion |= uint64_t(_uBuild) << 16; - _uVersion |= _uRevision; - return _uVersion; - } - -#ifdef __YY_Thunks_Unit_Test - EXTERN_C uint64_t g_uSystemVersion = 0; -#endif - - __forceinline uint64_t __fastcall GetSystemVersion() - { -#ifdef __YY_Thunks_Unit_Test - if (g_uSystemVersion) - return g_uSystemVersion; -#endif - const auto _pPeb = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; - return internal::MakeVersion(_pPeb->OSMajorVersion, _pPeb->OSMinorVersion, _pPeb->OSBuildNumber); - } - - 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) - static void* __fastcall Alloc(_In_ size_t _cbBytes, DWORD _fFlags = 0) - { - return HeapAlloc(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, _fFlags, _cbBytes); - } - - _Check_return_ - _Ret_maybenull_ - _Post_writable_byte_size_(_cbBytes) - static void* __fastcall ReAlloc(_Pre_maybenull_ _Post_invalid_ void* _pAddress, _In_ size_t _cbBytes) - { - auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; - if (_pAddress) - { - return HeapReAlloc(_hProcessHeap, 0, _pAddress, _cbBytes); - } - else - { - return HeapAlloc(_hProcessHeap, 0, _cbBytes); - } - } - - static void __fastcall Free(_Pre_maybenull_ _Post_invalid_ void* _pAddress) - { - if(_pAddress) - HeapFree(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, 0, _pAddress); - } - - template - _Success_(return != NULL) _Check_return_ _Ret_maybenull_ - _CRTALLOCATOR - inline Type* __fastcall New(Args&&... args) - { - Type* _pType = (Type*)Alloc(sizeof(Type)); - if (_pType) - new (_pType) Type(std::forward(args)...); - - return _pType; - } - - template - inline void __fastcall Delete(_Pre_maybenull_ _Post_invalid_ T* _p) - { - if (_p) - { - _p->~T(); - Free(_p); - } - } - - class CppAlloc - { - public: - _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR - void* __CRTDECL operator new( - size_t _Size - ) - { - return Alloc(_Size); - } - - _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR - void* __CRTDECL operator new( - size_t _Size, - ::std::nothrow_t const& - ) noexcept - { - return Alloc(_Size); - } - - _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR - void* __CRTDECL operator new[]( - size_t _Size - ) - { - return Alloc(_Size); - } - - _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR - void* __CRTDECL operator new[]( - size_t _Size, - ::std::nothrow_t const& - ) noexcept - { - return Alloc(_Size); - } - - /// - /// placement new - /// - /// - /// - /// - void* __CRTDECL operator new( - size_t _Size, - void* _Block - ) noexcept - { - return _Block; - } - - void __CRTDECL operator delete( - void* _Block - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete( - void* _Block, - ::std::nothrow_t const& - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete[]( - void* _Block - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete[]( - void* _Block, - ::std::nothrow_t const& - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete( - void* _Block, - size_t _Size - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete[]( - void* _Block, - size_t _Size - ) noexcept - { - Free(_Block); - } - - void __CRTDECL operator delete( - void* _Block, - void* - ) noexcept - { - } - }; - - - //代码块,分割任务 - template - auto __forceinline Block(Callback&& _Callback, Params&&... args) -> decltype(_Callback(args...)) - { - return _Callback(args...); - } - - static DWORD __fastcall NtStatusToDosError( - _In_ NTSTATUS Status - ) - { - if (STATUS_TIMEOUT == Status) - { - /* - https://github.com/Chuyu-Team/YY-Thunks/issues/10 - - 用户报告,Windows XP 无法转换 STATUS_TIMEOUT。实际结果也是rubin,因此,特殊处理一下。 - */ - return ERROR_TIMEOUT; - } - -#if !defined(__USING_NTDLL_LIB) - const auto RtlNtStatusToDosError = try_get_RtlNtStatusToDosError(); - if (!RtlNtStatusToDosError) - { - //如果没有RtlNtStatusToDosError就直接设置Status代码吧,反正至少比没有错误代码强 - return Status; - } -#endif - return RtlNtStatusToDosError(Status); - } - - static DWORD __fastcall BaseSetLastNTError( - _In_ NTSTATUS Status - ) - { - auto lStatus = NtStatusToDosError(Status); - SetLastError(lStatus); - return lStatus; - } - - static __analysis_noreturn void __fastcall RaiseStatus(NTSTATUS Status) - { - RaiseException(Status, EXCEPTION_NONCONTINUABLE, 0, NULL); - } - - static LARGE_INTEGER* __fastcall BaseFormatTimeOut(LARGE_INTEGER* Timeout, DWORD dwMilliseconds) - { - if (dwMilliseconds == INFINITE) - return nullptr; - - Timeout->QuadPart = -10000ll * dwMilliseconds; - - return Timeout; - } - - static LSTATUS __fastcall Basep8BitStringToStaticUnicodeString(UNICODE_STRING* pDst, LPCSTR Src) - { - const UINT CodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - - auto cchDst = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, Src, -1, pDst->Buffer, pDst->MaximumLength / sizeof(wchar_t)); - if (cchDst <= 0) - { - return GetLastError(); - } - cchDst *= sizeof(wchar_t); - if (cchDst > MAXUINT16) - { - return ERROR_BAD_PATHNAME; - } - - pDst->Length = static_cast(cchDst); - return ERROR_SUCCESS; - } - - static BOOL __fastcall BasepGetVolumeGUIDFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeGUID[MAX_PATH]) - { -#define __szVolumeMountPointPrefix__ L"\\\\?\\GLOBALROOT" - - //一个设备名称 512 长度够多了吧? - wchar_t szVolumeMountPoint[512]; - - //检查缓冲区是否充足 - auto cbBufferNeed = sizeof(__szVolumeMountPointPrefix__) + NtName->Length; - - if (cbBufferNeed > sizeof(szVolumeMountPoint)) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - - memcpy(szVolumeMountPoint, __szVolumeMountPointPrefix__, sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0])); - memcpy((char*)szVolumeMountPoint + sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0]), NtName->Buffer, NtName->Length); - - szVolumeMountPoint[cbBufferNeed / 2 - 1] = L'\0'; - - - return GetVolumeNameForVolumeMountPointW(szVolumeMountPoint, szVolumeGUID, MAX_PATH); - -#undef __szVolumeMountPointPrefix__ - } - - static BOOL __fastcall BasepGetVolumeDosLetterNameFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeDosLetter[MAX_PATH]) - { - wchar_t szVolumeName[MAX_PATH]; - - if (!BasepGetVolumeGUIDFromNTName(NtName, szVolumeName)) - { - return FALSE; - } - - DWORD cchVolumePathName = 0; - - if (!GetVolumePathNamesForVolumeNameW(szVolumeName, szVolumeDosLetter + 4, MAX_PATH - 4, &cchVolumePathName)) - { - return FALSE; - } - - szVolumeDosLetter[0] = L'\\'; - szVolumeDosLetter[1] = L'\\'; - szVolumeDosLetter[2] = L'?'; - szVolumeDosLetter[3] = L'\\'; - - return TRUE; - } - - static unsigned __fastcall CharToHex(_In_ wchar_t _ch) - { - if (_ch >= L'0' && _ch <= L'9') - { - return _ch - L'0'; - } - else if (_ch >= L'A' && _ch <= L'F') - { - return _ch - L'A' + 0xA; - } - else if (_ch >= L'a' && _ch <= L'f') - { - return _ch - L'a' + 0xA; - } - else - { - return -1; - } - } - - static BOOL __fastcall StringToGuid(_In_z_ const wchar_t* _szInput, _Out_ GUID* _pId) - { - *_pId = GUID{}; - - if (!_szInput) - return FALSE; - - if (*_szInput == L'{') - ++_szInput; - -#define _IS_HEX_CHAR(C) (CharToHex(C) != (unsigned)-1) - - if (!(_IS_HEX_CHAR(_szInput[0]) && _IS_HEX_CHAR(_szInput[1]) && _IS_HEX_CHAR(_szInput[2]) && _IS_HEX_CHAR(_szInput[3]) - && _IS_HEX_CHAR(_szInput[4]) && _IS_HEX_CHAR(_szInput[5]) && _IS_HEX_CHAR(_szInput[6]) && _IS_HEX_CHAR(_szInput[7]) - && _szInput[8] == L'-' - && _IS_HEX_CHAR(_szInput[9]) && _IS_HEX_CHAR(_szInput[10]) && _IS_HEX_CHAR(_szInput[11]) && _IS_HEX_CHAR(_szInput[12]) - && _szInput[13] == L'-' - && _IS_HEX_CHAR(_szInput[14]) && _IS_HEX_CHAR(_szInput[15]) && _IS_HEX_CHAR(_szInput[16]) && _IS_HEX_CHAR(_szInput[17]) - && _szInput[18] == L'-' - && _IS_HEX_CHAR(_szInput[19]) && _IS_HEX_CHAR(_szInput[20]) && _IS_HEX_CHAR(_szInput[21]) && _IS_HEX_CHAR(_szInput[22]) - && _szInput[23] == L'-' - && _IS_HEX_CHAR(_szInput[24]) && _IS_HEX_CHAR(_szInput[25]) && _IS_HEX_CHAR(_szInput[26]) && _IS_HEX_CHAR(_szInput[27]) - && _IS_HEX_CHAR(_szInput[28]) && _IS_HEX_CHAR(_szInput[29]) && _IS_HEX_CHAR(_szInput[30]) && _IS_HEX_CHAR(_szInput[31]) - && _IS_HEX_CHAR(_szInput[32]) && _IS_HEX_CHAR(_szInput[33]) && _IS_HEX_CHAR(_szInput[34]) && _IS_HEX_CHAR(_szInput[35]))) - { - return FALSE; - } -#undef _IS_HEX_CHAR - - _pId->Data1 = (CharToHex(_szInput[0]) << 28) | (CharToHex(_szInput[1]) << 24) | (CharToHex(_szInput[2]) << 20) | (CharToHex(_szInput[3]) << 16) - | (CharToHex(_szInput[4]) << 12) | (CharToHex(_szInput[5]) << 8) | (CharToHex(_szInput[6]) << 4) | (CharToHex(_szInput[7]) << 0); - - _pId->Data2 = (CharToHex(_szInput[9]) << 12) | (CharToHex(_szInput[10]) << 8) | (CharToHex(_szInput[11]) << 4) | (CharToHex(_szInput[12]) << 0); - - _pId->Data3 = (CharToHex(_szInput[14]) << 12) | (CharToHex(_szInput[15]) << 8) | (CharToHex(_szInput[16]) << 4) | (CharToHex(_szInput[17]) << 0); - - _pId->Data4[0] = (CharToHex(_szInput[19]) << 4) | (CharToHex(_szInput[20]) << 0); - _pId->Data4[1] = (CharToHex(_szInput[21]) << 4) | (CharToHex(_szInput[22]) << 0); - _pId->Data4[2] = (CharToHex(_szInput[24]) << 4) | (CharToHex(_szInput[25]) << 0); - _pId->Data4[3] = (CharToHex(_szInput[26]) << 4) | (CharToHex(_szInput[27]) << 0); - _pId->Data4[4] = (CharToHex(_szInput[28]) << 4) | (CharToHex(_szInput[29]) << 0); - _pId->Data4[5] = (CharToHex(_szInput[30]) << 4) | (CharToHex(_szInput[31]) << 0); - _pId->Data4[6] = (CharToHex(_szInput[32]) << 4) | (CharToHex(_szInput[33]) << 0); - _pId->Data4[7] = (CharToHex(_szInput[34]) << 4) | (CharToHex(_szInput[35]) << 0); - return TRUE; - } - - template - static bool __fastcall StringStartsWithI(_In_z_ const Char1* _szStr, _In_z_ const Char2* _szStartsWith, _Outptr_opt_result_z_ const Char1** _szEnd = nullptr) - { - if (_szEnd) - *_szEnd = _szStr; - - if (_szStr == (Char1*)_szStartsWith) - return true; - - if (_szStr == nullptr) - return false; - if (_szStartsWith == nullptr) - return false; - - for (; *_szStartsWith;++_szStr, ++_szStartsWith) - { - if (*_szStr == *_szStartsWith) - { - continue; - } - else if (__ascii_tolower(*_szStr) == __ascii_tolower(*_szStartsWith)) - { - continue; - } - - return false; - } - if (_szEnd) - *_szEnd = _szStr; - return true; - } - - template - static bool __fastcall StringToUint32(_In_z_ const Char* _szStr, _Out_ DWORD* _puResult, _Outptr_opt_result_z_ Char const** _pszEnd = nullptr) - { - auto _szEnd = _szStr; - - if (_pszEnd) - *_pszEnd = _szEnd; - - *_puResult = 0; - - DWORD64 _uResult64 = 0; - for (;;++_szEnd) - { - if (*_szEnd <= '9' && *_szEnd >= '0') - { - _uResult64 *= 10; - _uResult64 += *_szEnd - '0'; - - // 溢出 - if (_uResult64 > 0xFFFFFFFFull) - { - return false; - } - } - else - { - break; - } - } - - if (_szStr == _szEnd) - return false; - - *_puResult = static_cast(_uResult64); - if (_pszEnd) - *_pszEnd = _szEnd; - return true; - } - - - /// - /// 计算字符串长度,某些场景我们特意不依赖wcslen之类的,防止发生死锁。 - /// - /// - /// - /// - /// - template - constexpr size_t StringLength(_In_z_ const Char* _szString, size_t _cchMaxLength = -1) - { - if (!_szString) - return 0; - - size_t _cchString = 0; - for (;_cchMaxLength && *_szString;--_cchMaxLength, ++_szString) - { - ++_cchString; - } - - return _cchString; - } - - template - class StringBuffer - { - public: - Char* szBuffer = nullptr; - size_t uLength = 0; - size_t uBufferLength = 0; - bool bCanFree = false; - - constexpr StringBuffer() - : bCanFree(true) - { - } - - constexpr StringBuffer(StringBuffer&& _Other) noexcept - : szBuffer(_Other.szBuffer) - , uLength(_Other.uLength) - , uBufferLength(_Other.uBufferLength) - , bCanFree(_Other.bCanFree) - { - _Other.szBuffer = nullptr; - _Other.uLength = 0; - _Other.uBufferLength = 0; - } - - - constexpr StringBuffer(Char* _szBuffer, size_t _uBufferLength) - : szBuffer(_szBuffer) - , uLength(0) - , uBufferLength(_uBufferLength) - { - if (uBufferLength) - { - *szBuffer = '\0'; - } - } - - StringBuffer(const StringBuffer&) = delete; - - ~StringBuffer() - { - if (bCanFree) - { - internal::Free(szBuffer); - } - } - - template - bool __fastcall AppendString(_In_z_ const Char2* _szSrc) - { - if (_szSrc == nullptr || *_szSrc == '\0') - return true; - - TryBuy(128); - - if (uLength == uBufferLength) - return false; - - for (auto _uLengthNew = uLength; _uLengthNew != uBufferLength; ++_uLengthNew, ++_szSrc) - { - szBuffer[_uLengthNew] = *_szSrc; - if (*_szSrc == '\0') - { - uLength = _uLengthNew; - return true; - } - TryBuy(); - } - - szBuffer[uLength] = '\0'; - return false; - } - - template - bool __fastcall AppendChar(_In_z_ Char2 _Ch) - { - if (_Ch == '\0') - return true; - TryBuy(); - const auto _uNew = uLength + 1; - if (_uNew >= uBufferLength) - return false; - szBuffer[uLength] = _Ch; - szBuffer[_uNew] = '\0'; - uLength = _uNew; - return true; - } - - bool __fastcall AppendUint32(_In_ DWORD _uAppdendData) - { - TryBuy(32); - - if (uLength == uBufferLength) - return false; - - auto _uLengthNew = uLength; - for(; _uLengthNew != uBufferLength;) - { - const auto _uData = _uAppdendData % 10; - _uAppdendData /= 10; - - szBuffer[_uLengthNew] = static_cast('0' + _uData); - ++_uLengthNew; - if (_uAppdendData == 0) - { - if (_uLengthNew == uBufferLength) - { - break; - } - szBuffer[_uLengthNew] = '\0'; - auto _szStart = szBuffer + uLength; - auto _szLast = szBuffer + _uLengthNew; - - for (; _szStart < _szLast;) - { - --_szLast; - const auto _ch = *_szLast; - *_szLast = *_szStart; - *_szStart = _ch; - - ++_szStart; - } - uLength = _uLengthNew; - return true; - } - } - - *szBuffer = '\0'; - return false; - } - - _Ret_z_ const Char* __fastcall GetC_String() const - { - return szBuffer ? szBuffer : (Char*)L""; - } - - _Ret_maybenull_ Char* __fastcall GetBuffer(size_t _cNewBufferLength) - { - // 字符串有一个末尾 0 - ++_cNewBufferLength; - if (uBufferLength > _cNewBufferLength) - return szBuffer; - - if (!bCanFree) - return nullptr; - - auto _szNewBuffer = (Char*)internal::ReAlloc(szBuffer, _cNewBufferLength * sizeof(Char)); - if (!_szNewBuffer) - return nullptr; - - szBuffer = _szNewBuffer; - uBufferLength = _cNewBufferLength; - szBuffer[uLength] = 0; - return _szNewBuffer; - } - - void __fastcall SetLength(size_t _cNewLength) - { - if (_cNewLength == uLength) - { - return; - } - else if (uBufferLength <= _cNewLength) - { - __debugbreak(); - return; - } - - uLength = _cNewLength; - szBuffer[uLength] = '\0'; - } - - void TryBuy(DWORD _uAppdendData = 1) - { - if (bCanFree ==false || _uAppdendData == 0) - return; - - auto _uNew = uLength + _uAppdendData; - if (_uNew >= uBufferLength) - { - GetBuffer(max(uBufferLength * 2, _uNew)); - } - } - - bool __fastcall AppendGUID(_In_ const GUID& _Id) - { - TryBuy(36); - - const auto _uLengthNew = uLength + 36; - if (_uLengthNew >= uBufferLength) - { - return false; - } - - // C0F8B35B-3CA6-4E57-9B65-B654B33AE583 - auto _szHexChar = "0123456789abcdef"; - auto _pBuffer = szBuffer + uLength; - *_pBuffer++ = _szHexChar[_Id.Data1 >> 28]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 24) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 20) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 16) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 12) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 8) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data1 >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data1 & 0xF]; - - *_pBuffer++ = '-'; - *_pBuffer++ = _szHexChar[(_Id.Data2 >> 12) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data2 >> 8) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data2 >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data2 & 0xF]; - - *_pBuffer++ = '-'; - *_pBuffer++ = _szHexChar[(_Id.Data3 >> 12) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data3 >> 8) & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data3 >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data3 & 0xF]; - - *_pBuffer++ = '-'; - *_pBuffer++ = _szHexChar[(_Id.Data4[0] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[0] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[1] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[1] & 0xF]; - - *_pBuffer++ = '-'; - *_pBuffer++ = _szHexChar[(_Id.Data4[2] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[2] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[3] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[3] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[4] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[4] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[5] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[5] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[6] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[6] & 0xF]; - *_pBuffer++ = _szHexChar[(_Id.Data4[7] >> 4) & 0xF]; - *_pBuffer++ = _szHexChar[_Id.Data4[7] & 0xF]; - *_pBuffer = 0; - uLength = _uLengthNew; - return true; - } - }; - - static LSTATUS Convert(_In_NLS_string_(_cchSrc) LPCWSTR _szSrc, _In_ int _cchSrc, StringBuffer* _pBuffer) - { - _pBuffer->SetLength(0); - if (_cchSrc == 0) - return ERROR_SUCCESS; - - if (_cchSrc < 0) - { - const auto _cchLength = _szSrc ? wcslen(_szSrc) : size_t(0); - if(_cchLength > MAXINT32) - return ERROR_NOT_ENOUGH_MEMORY; - - _cchSrc = static_cast(_cchLength); - if (_cchSrc == 0) - return ERROR_SUCCESS; - } - - const auto _cchDst = WideCharToMultiByte(CP_ACP, 0, _szSrc, _cchSrc, nullptr, 0, nullptr, nullptr); - if (_cchDst > 0) - { - auto _szDst = _pBuffer->GetBuffer(_cchDst); - if (!_szDst) - return ERROR_NOT_ENOUGH_MEMORY; - - WideCharToMultiByte(CP_ACP, 0, _szSrc, _cchSrc, _szDst, _cchDst, nullptr, nullptr); - _pBuffer->SetLength(_cchDst); - } - return ERROR_SUCCESS; - } - - static bool __fastcall IsEqualI(const UNICODE_STRING& _Left, const UNICODE_STRING& _Right) - { - if (_Left.Length != _Right.Length) - return false; - - return StringCompareIgnoreCaseByAscii(_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; - } - - static constexpr UNICODE_STRING __fastcall MakeNtString(_In_z_ const wchar_t* _szString) - { - const auto _cbString = StringLength(_szString) * sizeof(_szString[0]); - UNICODE_STRING _Result = { (USHORT)min(UINT16_MAX, _cbString), (USHORT)min(UINT16_MAX, _cbString + sizeof(_szString[0])), const_cast(_szString) }; - return _Result; - } - - static constexpr ANSI_STRING __fastcall MakeNtString(_In_z_ const char* _szString) - { - const auto _cbString = StringLength(_szString) * sizeof(_szString[0]); - - ANSI_STRING _Result = { (USHORT)min(UINT16_MAX, _cbString), (USHORT)min(UINT16_MAX, _cbString + sizeof(_szString[0])), const_cast(_szString)}; - return _Result; - } - - 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 - -#include "ThreadRunner.h" - -#define _DEFINE_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE) _LCRT_DEFINE_IAT_SYMBOL(_PREFIX ## _FUNCTION, _SIZE) -#define _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE) _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL(_FUNCTION, _SIZE, _PREFIX ## _FUNCTION) - -//导入实际的实现 -#define YY_Thunks_Implemented -#define __DEFINE_THUNK_IMP_PREFIX(_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ - static decltype(_CRT_CONCATENATE_(_PREFIX, _FUNCTION))* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept \ - { \ - __CHECK_UNIT_TEST_BOOL(_FUNCTION); \ - __declspec(allocate(".YYThr$AAA")) static void* _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ - reinterpret_cast(&_CRT_CONCATENATE(try_get_, _FUNCTION)); \ - /*为了避免编译器将 YYThr$AAA 节优化掉*/ \ - __foreinclude(_CRT_CONCATENATE(pInit_ ,_FUNCTION)); \ - __declspec(allocate(".YYThu$AAB")) static void* _CRT_CONCATENATE(pFun_, _FUNCTION); \ - static const ProcInfo _ProcInfo = \ - { \ - _CRT_STRINGIZE(_FUNCTION), \ - &_CRT_CONCATENATE(try_get_module_, _MODULE), \ -__if_exists(YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION)) \ -{ \ - &YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION) \ -} \ - }; \ - return reinterpret_cast(try_get_function( \ - &_CRT_CONCATENATE(pFun_ ,_FUNCTION), \ - _ProcInfo)); \ - } \ - _DEFINE_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE); \ - _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE); \ - EXTERN_C _RETURN_ _CONVENTION_ _CRT_CONCATENATE_(_PREFIX, _FUNCTION)(__VA_ARGS__) - -#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) __DEFINE_THUNK_IMP_PREFIX(__FALLBACK_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, __VA_ARGS__) - -#include "YY_Thunks_List.hpp" - -#undef __DEFINE_THUNK -#undef YY_Thunks_Implemented - -static HMODULE __fastcall try_get_module(volatile HMODULE* pModule, const wchar_t* module_name, int Flags) noexcept -{ - // First check to see if we've cached the module handle: - if (HMODULE const cached_handle = __crt_interlocked_read_pointer(pModule)) - { - if (cached_handle == INVALID_HANDLE_VALUE) - { - return nullptr; - } - - return cached_handle; - } - - // If we haven't yet cached the module handle, try to load the library. If - // this fails, cache the sentinel handle value INVALID_HANDLE_VALUE so that - // we don't attempt to load the module again: - HMODULE new_handle = NULL; - - if (__pfnYY_Thunks_CustomLoadLibrary) - { - new_handle = __pfnYY_Thunks_CustomLoadLibrary(module_name, Flags); - } - - if (new_handle) - { - // 使用 CustomLoadLibrary的结果 - if (new_handle == INVALID_HANDLE_VALUE) - new_handle = nullptr; - } - else if (Flags & USING_GET_MODULE_HANDLE) - { - new_handle = GetModuleHandleW(module_name); - } - else - { - // 我们不能直接使用 LoadLibraryExW,因为它可能被Thunk。 - __if_exists(YY::Thunks::try_get_LoadLibraryExW) - { - const auto LoadLibraryExW = YY::Thunks::try_get_LoadLibraryExW(); - if (!LoadLibraryExW) - return nullptr; - } - - if (Flags & LOAD_AS_DATA_FILE) - { - new_handle = LoadLibraryExW(module_name, NULL, LOAD_LIBRARY_AS_DATAFILE); - } - else if (Flags & USING_UNSAFE_LOAD) - { - new_handle = LoadLibraryExW(module_name, nullptr, 0); - } - else - { - // 使用DLL安全加载 -#if (YY_Thunks_Target < __WindowsNT6_2) - if (!try_get_AddDllDirectory()) - { -#if !defined(__USING_NTDLL_LIB) - const auto LdrLoadDll = try_get_LdrLoadDll(); - if (!LdrLoadDll) - return nullptr; -#endif - wchar_t szFilePathBuffer[MAX_PATH] = {}; - const auto _cchSystemPath = GetSystemDirectoryW(szFilePathBuffer, _countof(szFilePathBuffer)); - if (_cchSystemPath == 0 || _cchSystemPath >= _countof(szFilePathBuffer)) - { - // 回落普通加载,按理说 GetSystemDirectoryW不应该发生这样的失败。 - new_handle = LoadLibraryExW(module_name, nullptr, 0); - } - else - { - auto _sModuleName = YY::Thunks::internal::MakeNtString(module_name); - LdrLoadDll(szFilePathBuffer, nullptr, &_sModuleName, &new_handle); - } - } - else -#endif - { - new_handle = LoadLibraryExW(module_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); - } - } - } - - if (!new_handle) - { - if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(pModule, INVALID_HANDLE_VALUE)) - { - _ASSERTE(cached_handle == INVALID_HANDLE_VALUE); - } - - return nullptr; - } - - // Swap the new handle into the cache. If the cache no longer contained a - // null handle, then some other thread loaded the module and cached the - // handle while we were doing the same. In that case, we free the handle - // once to maintain the reference count: - if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(pModule, new_handle)) - { - _ASSERTE(cached_handle == new_handle); - FreeLibrary(new_handle); - } - - return new_handle; -} - -static __forceinline void* __fastcall try_get_proc_address_from_dll( - const ProcInfo& _ProcInfo - ) noexcept -{ - HMODULE const module_handle = _ProcInfo.pfnGetModule(); - if (!module_handle) - { - return nullptr; - } - - // 无法直接调用GetProcAddress,因为GetProcAddress可能被Thunk - // 我们需要严格判断,避免发生死锁。 -#if defined(__USING_NTDLL_LIB) - void* _pProc = nullptr; - if (uintptr_t(_ProcInfo.szProcName) > UINT16_MAX) - { - ANSI_STRING _sFunctionName = YY::Thunks::internal::MakeNtString(_ProcInfo.szProcName); - LdrGetProcedureAddress(module_handle, &_sFunctionName, 0, &_pProc); - } - else - { - LdrGetProcedureAddress(module_handle, nullptr, (WORD)uintptr_t(_ProcInfo.szProcName), &_pProc); - } - return _pProc; -#else // !defined(__USING_NTDLL_LIB) - __if_exists(YY::Thunks::try_get_GetProcAddress) - { - const auto GetProcAddress = YY::Thunks::try_get_GetProcAddress(); - } - - return reinterpret_cast(GetProcAddress(module_handle, _ProcInfo.szProcName)); -#endif // defined(__USING_NTDLL_LIB) -} - -static __forceinline void* __fastcall try_get_proc_address_from_first_available_module( - const ProcInfo& _ProcInfo - ) noexcept -{ - if (_ProcInfo.pfnCustomGetProcAddress) - { - return _ProcInfo.pfnCustomGetProcAddress(_ProcInfo); - } - - return try_get_proc_address_from_dll(_ProcInfo); -} +/* +YY-Thunks支持的控制宏: +1. __FALLBACK_PREFIX:编译Lib库模式使用的API前缀修饰。一般来说只能为空或者传递 "YY_Thunks_"。 +2. __USING_NTDLL_LIB:假定构建环境存在ntdll.lib,这可以减少一些NTDLL相关函数的动态加载。 + +特殊支持的变通方案: +1. __ENABLE_WORKAROUND_ALL +启用所有兼容方案,即__ENABLE_WORKAROUND_1 ~ __ENABLE_WORKAROUND_N,全部开启。 + +2. __ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng +兼容方案1:让GetProcAddress也能取到ProcessPrng函数地址。某些代码可能强制依赖ProcessPrng。 + +3. __ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL +兼容方案2:Windows 8.1以前的版本对于匿名对象无法生效DACL。就会导致Chrome的CheckPlatformHandlePermissionsCorrespondToMode判断不准确。 +修复方案通过给匿名对象创建一个名字解决该问题。 + +特定项目的兼容方案: +1. __APPLY_CHROMIUM_WORKAROUNDS +开启Chrome项目的兼容能力,等效于同时指定__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng、__ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL。 + +*/ + +// 忽略非标准的 0 数组警告。 +#pragma warning(disable:4200) +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define _YY_APPLY_TO_LATE_BOUND_MODULES(_APPLY) \ + _APPLY(ntdll, "ntdll" , USING_GET_MODULE_HANDLE ) \ + _APPLY(kernel32, "kernel32" , USING_GET_MODULE_HANDLE ) \ + _APPLY(kernelbase, "kernelbase" , USING_GET_MODULE_HANDLE ) \ + _APPLY(cfgmgr32, "cfgmgr32" , 0 ) \ + _APPLY(crypt32, "crypt32" , 0 ) \ + _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 ) \ + _APPLY(dxva2, "dxva2" , 0 ) \ + _APPLY(esent, "esent" , 0 ) \ + _APPLY(uxtheme, "uxtheme" , 0 ) \ + _APPLY(uiautomationcore, "uiautomationcore" , 0 ) \ + _APPLY(psapi, "psapi" , 0 ) \ + _APPLY(pdh, "pdh" , 0 ) \ + _APPLY(version, "version" , 0 ) \ + _APPLY(advapi32, "advapi32" , 0 ) \ + _APPLY(bcrypt, "bcrypt" , 0 ) \ + _APPLY(bcryptprimitives, "bcryptprimitives" , 0 ) \ + _APPLY(user32, "user32" , 0 ) \ + _APPLY(ws2_32, "ws2_32" , 0 ) \ + _APPLY(shell32, "shell32" , 0 ) \ + _APPLY(shcore, "shcore" , 0 ) \ + _APPLY(shlwapi, "shlwapi" , 0 ) \ + _APPLY(setupapi, "setupapi" , 0 ) \ + _APPLY(ole32, "ole32" , 0 ) \ + _APPLY(iphlpapi, "iphlpapi" , 0 ) \ + _APPLY(userenv, "userenv" , 0 ) \ + _APPLY(mf, "mf" , 0 ) \ + _APPLY(mfplat, "mfplat" , 0 ) \ + _APPLY(mfreadwrite, "mfreadwrite" , 0 ) \ + _APPLY(ndfapi, "ndfapi" , 0 ) \ + _APPLY(bluetoothapis, "bluetoothapis" , 0 ) \ + _APPLY(netapi32, "netapi32" , 0 ) \ + _APPLY(powrprof, "powrprof" , 0 ) \ + _APPLY(propsys, "propsys" , 0 ) \ + _APPLY(wevtapi, "wevtapi" , 0 ) \ + _APPLY(winhttp, "winhttp" , 0 ) \ + _APPLY(winusb, "winusb" , 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 ) \ + _APPLY(api_ms_win_core_winrt_error_l1_1_0, "api-ms-win-core-winrt-error-l1-1-0" , 0 ) \ + _APPLY(api_ms_win_core_path_l1_1_0, "api-ms-win-core-path-l1-1-0" , 0 ) \ + _APPLY(api_ms_win_core_synch_l1_2_0, "api-ms-win-core-synch-l1-2-0" , 0 ) + + +//全局可能使用到的函数 +#define _YY_APPLY_TO_LATE_BOUND_FUNCTIONS(_APPLY) \ + _APPLY(NtOpenSection, ntdll ) \ + _APPLY(NtCreateFile, ntdll ) \ + _APPLY(NtClose, ntdll ) \ + _APPLY(NtQueryDirectoryFile, ntdll ) \ + _APPLY(NtQueryInformationFile, ntdll ) \ + _APPLY(NtQuerySystemInformation, ntdll ) \ + _APPLY(NtSetInformationFile, ntdll ) \ + _APPLY(RtlNtStatusToDosError, ntdll ) \ + _APPLY(RtlDetermineDosPathNameType_U, ntdll ) \ + _APPLY(RtlDosPathNameToNtPathName_U, ntdll ) \ + _APPLY(RtlDosPathNameToNtPathName_U_WithStatus, ntdll ) \ + _APPLY(RtlFreeUnicodeString, ntdll ) \ + _APPLY(NtQueryObject, ntdll ) \ + _APPLY(NtQueryInformationThread, ntdll ) \ + _APPLY(NtSetInformationThread, ntdll ) \ + _APPLY(NtQueryInformationProcess, ntdll ) \ + _APPLY(NtSetInformationProcess, ntdll ) \ + _APPLY(NtDeleteKey, ntdll ) \ + _APPLY(NtCreateKey, ntdll ) \ + _APPLY(NtOpenKey, ntdll ) \ + _APPLY(NtOpenKeyedEvent, ntdll ) \ + _APPLY(NtWaitForKeyedEvent, ntdll ) \ + _APPLY(NtReleaseKeyedEvent, ntdll ) \ + _APPLY(RtlAdjustPrivilege, ntdll ) \ + _APPLY(RtlPcToFileHeader, ntdll ) \ + _APPLY(LdrAddRefDll, ntdll ) \ + _APPLY(RtlWow64EnableFsRedirectionEx, ntdll ) \ + _APPLY(LdrLoadDll, ntdll ) \ + _APPLY(RtlDllShutdownInProgress, ntdll ) \ + _APPLY(RtlCutoverTimeToSystemTime, ntdll ) \ + _APPLY(NtCancelIoFile, ntdll ) \ + _APPLY(NtWow64ReadVirtualMemory64, ntdll ) \ + _APPLY(RtlValidSid, ntdll ) \ + _APPLY(RtlValidAcl, ntdll ) \ + _APPLY(RtlFirstFreeAce, ntdll ) \ + _APPLY(RtlCopySid, ntdll ) \ + _APPLY(AddDllDirectory, kernel32 ) \ + _APPLY(SystemFunction036, advapi32 ) + + +#include +#include + +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +#define _WINSOCKAPI_ +#define PSAPI_VERSION 1 + +#if (YY_Thunks_Target < __WindowsNT6) +#define INITKNOWNFOLDERS +#endif + +#ifndef __WarningMessage__ +#define STRING2(x) #x +#define STRING(x) STRING2(x) +#define __WarningMessage__(msg) __pragma(message (__FILE__ "(" STRING(__LINE__) "): warning Thunks: " # msg)) +#endif + +#if !defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (defined(__ENABLE_WORKAROUND_ALL) || defined(__APPLY_CHROMIUM_WORKAROUNDS)) +#define __ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng 1 +#endif + +#if !defined(__ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL) && (defined(__ENABLE_WORKAROUND_ALL) || defined(__APPLY_CHROMIUM_WORKAROUNDS)) +#define __ENABLE_WORKAROUND_2_UNNAME_OBJECT_DACL 1 +#endif + +#ifndef __FALLBACK_PREFIX +#define __FALLBACK_PREFIX +#define __YY_Thunks_libs 0 +#else +#define __YY_Thunks_libs 1 +#endif + +#if !defined(__USING_NTDLL_LIB) && (__YY_Thunks_libs || YY_Thunks_Target >= __WindowsNT10_10240) +// lib模式下必然存在 ntdll.lib,此外最小支持Windows 10时,我们因为强制依赖Windows 10 SDK,所以也必然存在ntdll.lib。 +#define __USING_NTDLL_LIB 1 +#endif + +#define _Disallow_YY_KM_Namespace +#include "km.h" +#include +#include +#include +#include +#include + +#include + +EXTERN_C +BOOLEAN +__stdcall +SystemFunction036( + _Out_writes_bytes_(RandomBufferLength) PVOID RandomBuffer, + _In_ ULONG RandomBufferLength + ); + +EXTERN_C +BOOLEAN +__stdcall +RtlCutoverTimeToSystemTime( + PTIME_FIELDS CutoverTime, + PLARGE_INTEGER SystemTime, + PLARGE_INTEGER CurrentSystemTime, + BOOLEAN ThisYear + ); + +#include "YY_Thunks.h" + +#if (YY_Thunks_Target < __WindowsNT5_2_SP1) && !defined(__Comment_Lib_advapi32) +#define __Comment_Lib_advapi32 +#pragma comment(lib, "Advapi32.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_shlwapi) +#define __Comment_Lib_shlwapi +#pragma comment(lib, "Shlwapi.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_ws2_32) +#define __Comment_Lib_ws2_32 +#pragma comment(lib, "Ws2_32.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_version) +#define __Comment_Lib_version +#pragma comment(lib, "version.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_ole32) +#define __Comment_Lib_ole32 +#pragma comment(lib, "ole32.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_shell32) +#define __Comment_Lib_shell32 +#pragma comment(lib, "shell32.lib") +#endif + +// PSAPI2Kernel32.def +#if (YY_Thunks_Target < __WindowsNT6_1) && !defined(__Comment_Lib_psapi) +#define __Comment_Lib_psapi +#pragma comment(lib, "psapi.lib") +#endif + +#if (YY_Thunks_Target >= __WindowsNT6_3) && !defined(__Comment_Lib_shcore) +#define __Comment_Lib_shcore +#pragma comment(lib, "Shcore.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT6_3) && !defined(__Comment_Lib_gdi32) +#define __Comment_Lib_gdi32 +#pragma comment(lib, "Gdi32.lib") +#endif + +#if (YY_Thunks_Target < __WindowsNT10_10240) && !defined(__Comment_Lib_user32) +#define __Comment_Lib_user32 +#pragma comment(lib, "User32.lib") +#endif + +#if defined(__USING_NTDLL_LIB) +#pragma comment(lib, "ntdll.lib") +#endif + +#include + +//展开函数的所有的 声明 以及 try_get_ 函数 +#define __DEFINE_THUNK_EXTERN_PREFIX(_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ + __APPLY_UNIT_TEST_BOOL(_FUNCTION); \ + EXTERN_C _RETURN_ _CONVENTION_ _CRT_CONCATENATE_(_PREFIX, _FUNCTION)(__VA_ARGS__); \ + static decltype(_CRT_CONCATENATE_(_PREFIX, _FUNCTION))* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept; \ + __if_not_exists(_CRT_CONCATENATE(try_get_, _FUNCTION)) + +#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) __DEFINE_THUNK_EXTERN_PREFIX(__FALLBACK_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, __VA_ARGS__) + +#include "Thunks\YY_Thunks_List.hpp" + +#undef __DEFINE_THUNK + +namespace YY::Thunks::internal +{ + namespace + { + inline UINT8 __fastcall BitsCount(ULONG32 _fBitMask) + { +#if defined(_M_IX86) || defined(_M_AMD64) + return static_cast(__popcnt(_fBitMask)); +#else + _fBitMask = (_fBitMask & 0x55555555) + ((_fBitMask >> 1) & 0x55555555); + _fBitMask = (_fBitMask & 0x33333333) + ((_fBitMask >> 2) & 0x33333333); + _fBitMask = (_fBitMask & 0x0f0f0f0f) + ((_fBitMask >> 4) & 0x0f0f0f0f); + _fBitMask = (_fBitMask & 0x00ff00ff) + ((_fBitMask >> 8) & 0x00ff00ff); + _fBitMask = (_fBitMask & 0x0000ffff) + ((_fBitMask >> 16) & 0x0000ffff); + return static_cast(_fBitMask); +#endif + } + + inline UINT8 __fastcall BitsCount(ULONG64 _fBitMask) + { +#if defined(_M_IX86) + return static_cast(__popcnt(static_cast(_fBitMask)) + __popcnt(static_cast(_fBitMask >> 32))); +#elif defined(_M_AMD64) + return static_cast(__popcnt64(_fBitMask)); +#else + _fBitMask = (_fBitMask & 0x55555555'55555555) + ((_fBitMask >> 1) & 0x55555555'55555555); + _fBitMask = (_fBitMask & 0x33333333'33333333) + ((_fBitMask >> 2) & 0x33333333'33333333); + _fBitMask = (_fBitMask & 0x0f0f0f0f'0f0f0f0f) + ((_fBitMask >> 4) & 0x0f0f0f0f'0f0f0f0f); + _fBitMask = (_fBitMask & 0x00ff00ff'00ff00ff) + ((_fBitMask >> 8) & 0x00ff00ff'00ff00ff); + _fBitMask = (_fBitMask & 0x0000ffff'0000ffff) + ((_fBitMask >> 16) & 0x0000ffff'0000ffff); + _fBitMask = (_fBitMask & 0x00000000'ffffffff) + ((_fBitMask >> 32) & 0x00000000'ffffffff); + return static_cast(_fBitMask); +#endif + } + + __forceinline constexpr uint64_t __fastcall MakeVersion(_In_ uint16_t _uMajor, _In_ uint16_t _uMinor, uint16_t _uBuild = 0, UINT16 _uRevision = 0) + { + uint64_t _uVersion = uint64_t(_uMajor) << 48; + _uVersion |= uint64_t(_uMinor) << 32; + _uVersion |= uint64_t(_uBuild) << 16; + _uVersion |= _uRevision; + return _uVersion; + } + +#ifdef __YY_Thunks_Unit_Test + EXTERN_C uint64_t g_uSystemVersion = 0; +#endif + + __forceinline uint64_t __fastcall GetSystemVersion() + { +#ifdef __YY_Thunks_Unit_Test + if (g_uSystemVersion) + return g_uSystemVersion; +#endif + const auto _pPeb = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; + return internal::MakeVersion(_pPeb->OSMajorVersion, _pPeb->OSMinorVersion, _pPeb->OSBuildNumber); + } + + 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) + static void* __fastcall Alloc(_In_ size_t _cbBytes, DWORD _fFlags = 0) + { + return HeapAlloc(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, _fFlags, _cbBytes); + } + + _Check_return_ + _Ret_maybenull_ + _Post_writable_byte_size_(_cbBytes) + static void* __fastcall ReAlloc(_Pre_maybenull_ _Post_invalid_ void* _pAddress, _In_ size_t _cbBytes) + { + auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + if (_pAddress) + { + return HeapReAlloc(_hProcessHeap, 0, _pAddress, _cbBytes); + } + else + { + return HeapAlloc(_hProcessHeap, 0, _cbBytes); + } + } + + static void __fastcall Free(_Pre_maybenull_ _Post_invalid_ void* _pAddress) + { + if(_pAddress) + HeapFree(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap, 0, _pAddress); + } + + template + _Success_(return != NULL) _Check_return_ _Ret_maybenull_ + _CRTALLOCATOR + inline Type* __fastcall New(Args&&... args) + { + Type* _pType = (Type*)Alloc(sizeof(Type)); + if (_pType) + new (_pType) Type(std::forward(args)...); + + return _pType; + } + + template + inline void __fastcall Delete(_Pre_maybenull_ _Post_invalid_ T* _p) + { + if (_p) + { + _p->~T(); + Free(_p); + } + } + + class CppAlloc + { + public: + _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR + void* __CRTDECL operator new( + size_t _Size + ) + { + return Alloc(_Size); + } + + _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR + void* __CRTDECL operator new( + size_t _Size, + ::std::nothrow_t const& + ) noexcept + { + return Alloc(_Size); + } + + _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR + void* __CRTDECL operator new[]( + size_t _Size + ) + { + return Alloc(_Size); + } + + _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR + void* __CRTDECL operator new[]( + size_t _Size, + ::std::nothrow_t const& + ) noexcept + { + return Alloc(_Size); + } + + /// + /// placement new + /// + /// + /// + /// + void* __CRTDECL operator new( + size_t _Size, + void* _Block + ) noexcept + { + return _Block; + } + + void __CRTDECL operator delete( + void* _Block + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete( + void* _Block, + ::std::nothrow_t const& + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete[]( + void* _Block + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete[]( + void* _Block, + ::std::nothrow_t const& + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete( + void* _Block, + size_t _Size + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete[]( + void* _Block, + size_t _Size + ) noexcept + { + Free(_Block); + } + + void __CRTDECL operator delete( + void* _Block, + void* + ) noexcept + { + } + }; + + + //代码块,分割任务 + template + auto __forceinline Block(Callback&& _Callback, Params&&... args) -> decltype(_Callback(args...)) + { + return _Callback(args...); + } + + static DWORD __fastcall NtStatusToDosError( + _In_ NTSTATUS Status + ) + { + if (STATUS_TIMEOUT == Status) + { + /* + https://github.com/Chuyu-Team/YY-Thunks/issues/10 + + 用户报告,Windows XP 无法转换 STATUS_TIMEOUT。实际结果也是rubin,因此,特殊处理一下。 + */ + return ERROR_TIMEOUT; + } + +#if !defined(__USING_NTDLL_LIB) + const auto RtlNtStatusToDosError = try_get_RtlNtStatusToDosError(); + if (!RtlNtStatusToDosError) + { + //如果没有RtlNtStatusToDosError就直接设置Status代码吧,反正至少比没有错误代码强 + return Status; + } +#endif + return RtlNtStatusToDosError(Status); + } + + static DWORD __fastcall BaseSetLastNTError( + _In_ NTSTATUS Status + ) + { + auto lStatus = NtStatusToDosError(Status); + SetLastError(lStatus); + return lStatus; + } + + static __analysis_noreturn void __fastcall RaiseStatus(NTSTATUS Status) + { + RaiseException(Status, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + + static LARGE_INTEGER* __fastcall BaseFormatTimeOut(LARGE_INTEGER* Timeout, DWORD dwMilliseconds) + { + if (dwMilliseconds == INFINITE) + return nullptr; + + Timeout->QuadPart = -10000ll * dwMilliseconds; + + return Timeout; + } + + static LSTATUS __fastcall Basep8BitStringToStaticUnicodeString(UNICODE_STRING* pDst, LPCSTR Src) + { + const UINT CodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + auto cchDst = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, Src, -1, pDst->Buffer, pDst->MaximumLength / sizeof(wchar_t)); + if (cchDst <= 0) + { + return GetLastError(); + } + cchDst *= sizeof(wchar_t); + if (cchDst > MAXUINT16) + { + return ERROR_BAD_PATHNAME; + } + + pDst->Length = static_cast(cchDst); + return ERROR_SUCCESS; + } + + static BOOL __fastcall BasepGetVolumeGUIDFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeGUID[MAX_PATH]) + { +#define __szVolumeMountPointPrefix__ L"\\\\?\\GLOBALROOT" + + //一个设备名称 512 长度够多了吧? + wchar_t szVolumeMountPoint[512]; + + //检查缓冲区是否充足 + auto cbBufferNeed = sizeof(__szVolumeMountPointPrefix__) + NtName->Length; + + if (cbBufferNeed > sizeof(szVolumeMountPoint)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + memcpy(szVolumeMountPoint, __szVolumeMountPointPrefix__, sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0])); + memcpy((char*)szVolumeMountPoint + sizeof(__szVolumeMountPointPrefix__) - sizeof(__szVolumeMountPointPrefix__[0]), NtName->Buffer, NtName->Length); + + szVolumeMountPoint[cbBufferNeed / 2 - 1] = L'\0'; + + + return GetVolumeNameForVolumeMountPointW(szVolumeMountPoint, szVolumeGUID, MAX_PATH); + +#undef __szVolumeMountPointPrefix__ + } + + static BOOL __fastcall BasepGetVolumeDosLetterNameFromNTName(const UNICODE_STRING* NtName, wchar_t szVolumeDosLetter[MAX_PATH]) + { + wchar_t szVolumeName[MAX_PATH]; + + if (!BasepGetVolumeGUIDFromNTName(NtName, szVolumeName)) + { + return FALSE; + } + + DWORD cchVolumePathName = 0; + + if (!GetVolumePathNamesForVolumeNameW(szVolumeName, szVolumeDosLetter + 4, MAX_PATH - 4, &cchVolumePathName)) + { + return FALSE; + } + + szVolumeDosLetter[0] = L'\\'; + szVolumeDosLetter[1] = L'\\'; + szVolumeDosLetter[2] = L'?'; + szVolumeDosLetter[3] = L'\\'; + + return TRUE; + } + + static unsigned __fastcall CharToHex(_In_ wchar_t _ch) + { + if (_ch >= L'0' && _ch <= L'9') + { + return _ch - L'0'; + } + else if (_ch >= L'A' && _ch <= L'F') + { + return _ch - L'A' + 0xA; + } + else if (_ch >= L'a' && _ch <= L'f') + { + return _ch - L'a' + 0xA; + } + else + { + return -1; + } + } + + static BOOL __fastcall StringToGuid(_In_z_ const wchar_t* _szInput, _Out_ GUID* _pId) + { + *_pId = GUID{}; + + if (!_szInput) + return FALSE; + + if (*_szInput == L'{') + ++_szInput; + +#define _IS_HEX_CHAR(C) (CharToHex(C) != (unsigned)-1) + + if (!(_IS_HEX_CHAR(_szInput[0]) && _IS_HEX_CHAR(_szInput[1]) && _IS_HEX_CHAR(_szInput[2]) && _IS_HEX_CHAR(_szInput[3]) + && _IS_HEX_CHAR(_szInput[4]) && _IS_HEX_CHAR(_szInput[5]) && _IS_HEX_CHAR(_szInput[6]) && _IS_HEX_CHAR(_szInput[7]) + && _szInput[8] == L'-' + && _IS_HEX_CHAR(_szInput[9]) && _IS_HEX_CHAR(_szInput[10]) && _IS_HEX_CHAR(_szInput[11]) && _IS_HEX_CHAR(_szInput[12]) + && _szInput[13] == L'-' + && _IS_HEX_CHAR(_szInput[14]) && _IS_HEX_CHAR(_szInput[15]) && _IS_HEX_CHAR(_szInput[16]) && _IS_HEX_CHAR(_szInput[17]) + && _szInput[18] == L'-' + && _IS_HEX_CHAR(_szInput[19]) && _IS_HEX_CHAR(_szInput[20]) && _IS_HEX_CHAR(_szInput[21]) && _IS_HEX_CHAR(_szInput[22]) + && _szInput[23] == L'-' + && _IS_HEX_CHAR(_szInput[24]) && _IS_HEX_CHAR(_szInput[25]) && _IS_HEX_CHAR(_szInput[26]) && _IS_HEX_CHAR(_szInput[27]) + && _IS_HEX_CHAR(_szInput[28]) && _IS_HEX_CHAR(_szInput[29]) && _IS_HEX_CHAR(_szInput[30]) && _IS_HEX_CHAR(_szInput[31]) + && _IS_HEX_CHAR(_szInput[32]) && _IS_HEX_CHAR(_szInput[33]) && _IS_HEX_CHAR(_szInput[34]) && _IS_HEX_CHAR(_szInput[35]))) + { + return FALSE; + } +#undef _IS_HEX_CHAR + + _pId->Data1 = (CharToHex(_szInput[0]) << 28) | (CharToHex(_szInput[1]) << 24) | (CharToHex(_szInput[2]) << 20) | (CharToHex(_szInput[3]) << 16) + | (CharToHex(_szInput[4]) << 12) | (CharToHex(_szInput[5]) << 8) | (CharToHex(_szInput[6]) << 4) | (CharToHex(_szInput[7]) << 0); + + _pId->Data2 = (CharToHex(_szInput[9]) << 12) | (CharToHex(_szInput[10]) << 8) | (CharToHex(_szInput[11]) << 4) | (CharToHex(_szInput[12]) << 0); + + _pId->Data3 = (CharToHex(_szInput[14]) << 12) | (CharToHex(_szInput[15]) << 8) | (CharToHex(_szInput[16]) << 4) | (CharToHex(_szInput[17]) << 0); + + _pId->Data4[0] = (CharToHex(_szInput[19]) << 4) | (CharToHex(_szInput[20]) << 0); + _pId->Data4[1] = (CharToHex(_szInput[21]) << 4) | (CharToHex(_szInput[22]) << 0); + _pId->Data4[2] = (CharToHex(_szInput[24]) << 4) | (CharToHex(_szInput[25]) << 0); + _pId->Data4[3] = (CharToHex(_szInput[26]) << 4) | (CharToHex(_szInput[27]) << 0); + _pId->Data4[4] = (CharToHex(_szInput[28]) << 4) | (CharToHex(_szInput[29]) << 0); + _pId->Data4[5] = (CharToHex(_szInput[30]) << 4) | (CharToHex(_szInput[31]) << 0); + _pId->Data4[6] = (CharToHex(_szInput[32]) << 4) | (CharToHex(_szInput[33]) << 0); + _pId->Data4[7] = (CharToHex(_szInput[34]) << 4) | (CharToHex(_szInput[35]) << 0); + return TRUE; + } + + template + static bool __fastcall StringStartsWithI(_In_z_ const Char1* _szStr, _In_z_ const Char2* _szStartsWith, _Outptr_opt_result_z_ const Char1** _szEnd = nullptr) + { + if (_szEnd) + *_szEnd = _szStr; + + if (_szStr == (Char1*)_szStartsWith) + return true; + + if (_szStr == nullptr) + return false; + if (_szStartsWith == nullptr) + return false; + + for (; *_szStartsWith;++_szStr, ++_szStartsWith) + { + if (*_szStr == *_szStartsWith) + { + continue; + } + else if (__ascii_tolower(*_szStr) == __ascii_tolower(*_szStartsWith)) + { + continue; + } + + return false; + } + if (_szEnd) + *_szEnd = _szStr; + return true; + } + + template + static bool __fastcall StringToUint32(_In_z_ const Char* _szStr, _Out_ DWORD* _puResult, _Outptr_opt_result_z_ Char const** _pszEnd = nullptr) + { + auto _szEnd = _szStr; + + if (_pszEnd) + *_pszEnd = _szEnd; + + *_puResult = 0; + + DWORD64 _uResult64 = 0; + for (;;++_szEnd) + { + if (*_szEnd <= '9' && *_szEnd >= '0') + { + _uResult64 *= 10; + _uResult64 += *_szEnd - '0'; + + // 溢出 + if (_uResult64 > 0xFFFFFFFFull) + { + return false; + } + } + else + { + break; + } + } + + if (_szStr == _szEnd) + return false; + + *_puResult = static_cast(_uResult64); + if (_pszEnd) + *_pszEnd = _szEnd; + return true; + } + + + /// + /// 计算字符串长度,某些场景我们特意不依赖wcslen之类的,防止发生死锁。 + /// + /// + /// + /// + /// + template + constexpr size_t StringLength(_In_z_ const Char* _szString, size_t _cchMaxLength = -1) + { + if (!_szString) + return 0; + + size_t _cchString = 0; + for (;_cchMaxLength && *_szString;--_cchMaxLength, ++_szString) + { + ++_cchString; + } + + return _cchString; + } + + template + class StringBuffer + { + public: + Char* szBuffer = nullptr; + size_t uLength = 0; + size_t uBufferLength = 0; + bool bCanFree = false; + + constexpr StringBuffer() + : bCanFree(true) + { + } + + constexpr StringBuffer(StringBuffer&& _Other) noexcept + : szBuffer(_Other.szBuffer) + , uLength(_Other.uLength) + , uBufferLength(_Other.uBufferLength) + , bCanFree(_Other.bCanFree) + { + _Other.szBuffer = nullptr; + _Other.uLength = 0; + _Other.uBufferLength = 0; + } + + + constexpr StringBuffer(Char* _szBuffer, size_t _uBufferLength) + : szBuffer(_szBuffer) + , uLength(0) + , uBufferLength(_uBufferLength) + { + if (uBufferLength) + { + *szBuffer = '\0'; + } + } + + StringBuffer(const StringBuffer&) = delete; + + ~StringBuffer() + { + if (bCanFree) + { + internal::Free(szBuffer); + } + } + + template + bool __fastcall AppendString(_In_z_ const Char2* _szSrc) + { + if (_szSrc == nullptr || *_szSrc == '\0') + return true; + + TryBuy(128); + + if (uLength == uBufferLength) + return false; + + for (auto _uLengthNew = uLength; _uLengthNew != uBufferLength; ++_uLengthNew, ++_szSrc) + { + szBuffer[_uLengthNew] = *_szSrc; + if (*_szSrc == '\0') + { + uLength = _uLengthNew; + return true; + } + TryBuy(); + } + + szBuffer[uLength] = '\0'; + return false; + } + + template + bool __fastcall AppendChar(_In_z_ Char2 _Ch) + { + if (_Ch == '\0') + return true; + TryBuy(); + const auto _uNew = uLength + 1; + if (_uNew >= uBufferLength) + return false; + szBuffer[uLength] = _Ch; + szBuffer[_uNew] = '\0'; + uLength = _uNew; + return true; + } + + bool __fastcall AppendUint32(_In_ DWORD _uAppdendData) + { + TryBuy(32); + + if (uLength == uBufferLength) + return false; + + auto _uLengthNew = uLength; + for(; _uLengthNew != uBufferLength;) + { + const auto _uData = _uAppdendData % 10; + _uAppdendData /= 10; + + szBuffer[_uLengthNew] = static_cast('0' + _uData); + ++_uLengthNew; + if (_uAppdendData == 0) + { + if (_uLengthNew == uBufferLength) + { + break; + } + szBuffer[_uLengthNew] = '\0'; + auto _szStart = szBuffer + uLength; + auto _szLast = szBuffer + _uLengthNew; + + for (; _szStart < _szLast;) + { + --_szLast; + const auto _ch = *_szLast; + *_szLast = *_szStart; + *_szStart = _ch; + + ++_szStart; + } + uLength = _uLengthNew; + return true; + } + } + + *szBuffer = '\0'; + return false; + } + + _Ret_z_ const Char* __fastcall GetC_String() const + { + return szBuffer ? szBuffer : (Char*)L""; + } + + _Ret_maybenull_ Char* __fastcall GetBuffer(size_t _cNewBufferLength) + { + // 字符串有一个末尾 0 + ++_cNewBufferLength; + if (uBufferLength > _cNewBufferLength) + return szBuffer; + + if (!bCanFree) + return nullptr; + + auto _szNewBuffer = (Char*)internal::ReAlloc(szBuffer, _cNewBufferLength * sizeof(Char)); + if (!_szNewBuffer) + return nullptr; + + szBuffer = _szNewBuffer; + uBufferLength = _cNewBufferLength; + szBuffer[uLength] = 0; + return _szNewBuffer; + } + + void __fastcall SetLength(size_t _cNewLength) + { + if (_cNewLength == uLength) + { + return; + } + else if (uBufferLength <= _cNewLength) + { + __debugbreak(); + return; + } + + uLength = _cNewLength; + szBuffer[uLength] = '\0'; + } + + void TryBuy(DWORD _uAppdendData = 1) + { + if (bCanFree ==false || _uAppdendData == 0) + return; + + auto _uNew = uLength + _uAppdendData; + if (_uNew >= uBufferLength) + { + GetBuffer(max(uBufferLength * 2, _uNew)); + } + } + + bool __fastcall AppendGUID(_In_ const GUID& _Id) + { + TryBuy(36); + + const auto _uLengthNew = uLength + 36; + if (_uLengthNew >= uBufferLength) + { + return false; + } + + // C0F8B35B-3CA6-4E57-9B65-B654B33AE583 + auto _szHexChar = "0123456789abcdef"; + auto _pBuffer = szBuffer + uLength; + *_pBuffer++ = _szHexChar[_Id.Data1 >> 28]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 24) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 20) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 16) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 12) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 8) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data1 >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data1 & 0xF]; + + *_pBuffer++ = '-'; + *_pBuffer++ = _szHexChar[(_Id.Data2 >> 12) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data2 >> 8) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data2 >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data2 & 0xF]; + + *_pBuffer++ = '-'; + *_pBuffer++ = _szHexChar[(_Id.Data3 >> 12) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data3 >> 8) & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data3 >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data3 & 0xF]; + + *_pBuffer++ = '-'; + *_pBuffer++ = _szHexChar[(_Id.Data4[0] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[0] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[1] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[1] & 0xF]; + + *_pBuffer++ = '-'; + *_pBuffer++ = _szHexChar[(_Id.Data4[2] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[2] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[3] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[3] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[4] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[4] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[5] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[5] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[6] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[6] & 0xF]; + *_pBuffer++ = _szHexChar[(_Id.Data4[7] >> 4) & 0xF]; + *_pBuffer++ = _szHexChar[_Id.Data4[7] & 0xF]; + *_pBuffer = 0; + uLength = _uLengthNew; + return true; + } + }; + + static LSTATUS Convert(_In_NLS_string_(_cchSrc) LPCWSTR _szSrc, _In_ int _cchSrc, StringBuffer* _pBuffer) + { + _pBuffer->SetLength(0); + if (_cchSrc == 0) + return ERROR_SUCCESS; + + if (_cchSrc < 0) + { + const auto _cchLength = _szSrc ? wcslen(_szSrc) : size_t(0); + if(_cchLength > MAXINT32) + return ERROR_NOT_ENOUGH_MEMORY; + + _cchSrc = static_cast(_cchLength); + if (_cchSrc == 0) + return ERROR_SUCCESS; + } + + const auto _cchDst = WideCharToMultiByte(CP_ACP, 0, _szSrc, _cchSrc, nullptr, 0, nullptr, nullptr); + if (_cchDst > 0) + { + auto _szDst = _pBuffer->GetBuffer(_cchDst); + if (!_szDst) + return ERROR_NOT_ENOUGH_MEMORY; + + WideCharToMultiByte(CP_ACP, 0, _szSrc, _cchSrc, _szDst, _cchDst, nullptr, nullptr); + _pBuffer->SetLength(_cchDst); + } + return ERROR_SUCCESS; + } + + static bool __fastcall IsEqualI(const UNICODE_STRING& _Left, const UNICODE_STRING& _Right) + { + if (_Left.Length != _Right.Length) + return false; + + return StringCompareIgnoreCaseByAscii(_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; + } + + static constexpr UNICODE_STRING __fastcall MakeNtString(_In_z_ const wchar_t* _szString) + { + const auto _cbString = StringLength(_szString) * sizeof(_szString[0]); + UNICODE_STRING _Result = { (USHORT)min(UINT16_MAX, _cbString), (USHORT)min(UINT16_MAX, _cbString + sizeof(_szString[0])), const_cast(_szString) }; + return _Result; + } + + static constexpr ANSI_STRING __fastcall MakeNtString(_In_z_ const char* _szString) + { + const auto _cbString = StringLength(_szString) * sizeof(_szString[0]); + + ANSI_STRING _Result = { (USHORT)min(UINT16_MAX, _cbString), (USHORT)min(UINT16_MAX, _cbString + sizeof(_szString[0])), const_cast(_szString)}; + return _Result; + } + + 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; + } + + static constexpr bool __fastcall UnicodeStringIsStaticBuffer(const UNICODE_STRING& _szString) noexcept + { + return LPBYTE(&_szString) + sizeof(_szString) == LPBYTE(_szString.Buffer); + } + + static constexpr LSTATUS __fastcall UnicodeStringAllocByteBuffer(UNICODE_STRING& _szString, size_t _cbNewBuffer) noexcept + { + if (_szString.MaximumLength >= _cbNewBuffer) + return ERROR_SUCCESS; + + if (UINT16_MAX < _cbNewBuffer) + return ERROR_TOO_MANY_NAMES; + + wchar_t* _pBuffer = nullptr; + if (UnicodeStringIsStaticBuffer(_szString)) + { + _pBuffer = (wchar_t*)internal::Alloc(_cbNewBuffer); + if (!_pBuffer) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + memcpy(_pBuffer, _szString.Buffer, _szString.Length); + } + else + { + _pBuffer = (wchar_t*)internal::ReAlloc(_szString.Buffer, _cbNewBuffer); + if (!_pBuffer) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + } + + _szString.Buffer = _pBuffer; + _szString.MaximumLength = _cbNewBuffer; + return ERROR_SUCCESS; + } + + static constexpr void __fastcall UnicodeStringFree(UNICODE_STRING& _szString) noexcept + { + if (!UnicodeStringIsStaticBuffer(_szString)) + { + internal::Free(_szString.Buffer); + _szString.Buffer = nullptr; + _szString.Length = 0; + _szString.MaximumLength = 0; + } + } + + static constexpr LSTATUS __fastcall UnicodeStringAppendByte(UNICODE_STRING& _szString, LPCWSTR szAppend, size_t _cbAppend) noexcept + { + if (_cbAppend == 0) + return ERROR_SUCCESS; + + const auto _cbLength = _szString.Length + _cbAppend; + if (_cbLength > UINT16_MAX) + { + return ERROR_TOO_MANY_NAMES; + } + + if (_cbLength > _szString.MaximumLength) + { + auto _cbAlloc = max(_szString.MaximumLength * 2, _cbLength + sizeof(wchar_t)); + if (_cbAlloc > UINT16_MAX) + _cbAlloc = _cbLength; + + auto _lStatus = UnicodeStringAllocByteBuffer(_szString, max(_cbAlloc, 128)); + if (_lStatus) + { + return _lStatus; + } + } + + memcpy(LPBYTE(_szString.Buffer) + _szString.Length, szAppend, _cbAppend); + _szString.Length = _cbLength; + if (_cbLength + sizeof(wchar_t) < _szString.MaximumLength) + { + *(wchar_t*)(LPBYTE(_szString.Buffer) + _cbLength) = L'\0'; + } + return ERROR_SUCCESS; + } + + static constexpr LSTATUS __fastcall UnicodeStringAppend(UNICODE_STRING& _szString, LPCWSTR szAppend, size_t _cchAppend) noexcept + { + return UnicodeStringAppendByte(_szString, szAppend, _cchAppend * sizeof(wchar_t)); + } + + static constexpr LSTATUS __fastcall UnicodeStringAppend(UNICODE_STRING& _szString, wchar_t _ch) noexcept + { + return UnicodeStringAppend(_szString, &_ch, 1); + } + + static constexpr UNICODE_STRING __fastcall UnicodeStringGetDir(LPCWSTR _szPath, size_t _cchPath) noexcept + { + auto _szPathEnd = _szPath + _cchPath; + for (; _szPathEnd != _szPath; ) + { + --_szPathEnd; + if (*_szPathEnd == L'\\' || *_szPathEnd == L'/') + { + ++_szPathEnd; + break; + } + } + + const auto _cbData = LPBYTE(_szPathEnd) - LPBYTE(_szPath); + return UNICODE_STRING{ USHORT(min(_cbData, UINT16_MAX)), USHORT(min(_cchPath * sizeof(wchar_t), UINT16_MAX)), PWSTR(_szPath)}; + } + + static constexpr UNICODE_STRING __fastcall UnicodeStringGetItem(LPWSTR _szString, LPWSTR _szStringEnd) noexcept + { + UNICODE_STRING _Result = { 0, 0, _szString }; + for (; _szString != _szStringEnd; ++_szString) + { + if (*_szString == L';') + { + _Result.Length = LPBYTE(_szString) - LPBYTE(_Result.Buffer); + _Result.MaximumLength = _Result.Length + sizeof(wchar_t); + return _Result; + } + } + + _Result.Length = LPBYTE(_szString) - LPBYTE(_Result.Buffer); + _Result.MaximumLength = _Result.Length; + return _Result; + } + + template + class UnicodeStringBuffer : public UNICODE_STRING + { + public: + static constexpr auto kcchStaticBuffer = _kcchStaticBuffer; + wchar_t StaticBuffer[kcchStaticBuffer]; + + constexpr UnicodeStringBuffer() + : UNICODE_STRING{0, _kcchStaticBuffer * sizeof(wchar_t), StaticBuffer } + , StaticBuffer{} + { + } + + ~UnicodeStringBuffer() + { + UnicodeStringFree(*this); + } + + UnicodeStringBuffer(const UnicodeStringBuffer&) = delete; + + LSTATUS __fastcall Append(LPCWSTR szAppend) noexcept + { + return UnicodeStringAppend(*this, szAppend, internal::StringLength(szAppend)); + } + + LSTATUS __fastcall Append(LPCWSTR szAppend, size_t _cchAppend) noexcept + { + return UnicodeStringAppend(*this, szAppend, _cchAppend); + } + + LSTATUS __fastcall Append(wchar_t _ch) noexcept + { + return UnicodeStringAppend(*this, &_ch, 1); + } + + LSTATUS __fastcall Append(const UNICODE_STRING& _szAppend) noexcept + { + return UnicodeStringAppend(*this, _szAppend.Buffer, _szAppend.Length / sizeof(wchar_t)); + } + + LSTATUS __fastcall AppendPath(_In_z_ LPCWSTR _szAppendPath) noexcept + { + for (; *_szAppendPath == L'\\' || *_szAppendPath == L'/'; ++_szAppendPath); + + if (*_szAppendPath == L'\0') + return ERROR_SUCCESS; + + auto _cchLength = Length / sizeof(wchar_t); + if (_cchLength) + { + const auto _ch = Buffer[_cchLength - 1]; + if (_ch != L'\\' && _ch != L'/') + { + auto _lStatus = Append(L'\\'); + if (_lStatus) + return _lStatus; + } + } + + return Append(_szAppendPath); + } + + LPWSTR __fastcall GetByteBuffer(size_t _cbLength) noexcept + { + if (UnicodeStringAllocByteBuffer(*this, _cbLength + sizeof(wchar_t))) + { + return nullptr; + } + + return Buffer; + } + + LPWSTR __fastcall GetBuffer(size_t _cchLength) noexcept + { + return GetByteBuffer(_cchLength * sizeof(wchar_t)); + } + + void __fastcall SetLength(size_t _cchLength) noexcept + { + return SetByteLength(_cchLength * sizeof(wchar_t)); + } + + void __fastcall SetByteLength(size_t _cbLength) noexcept + { + _ASSERT(_cbLength <= MaximumLength); + Length = _cbLength; + if (Length + 2 < MaximumLength) + { + *(wchar_t*)(LPBYTE(Buffer) + Length) = L'\0'; + } + } + + void __fastcall Empty() noexcept + { + SetByteLength(0); + } + + LPWSTR __fastcall GetAppendBuffer(size_t _cchAppendLength) noexcept + { + auto _pBuffer = GetByteBuffer(Length + (_cchAppendLength + 1) * sizeof(wchar_t)); + if (!_pBuffer) + return nullptr; + + return LPWSTR(LPBYTE(_pBuffer) + Length); + } + + void __fastcall SetAppendByteLength(size_t _cbLength) noexcept + { + SetByteLength(Length + _cbLength); + } + + void __fastcall SetAppendLength(size_t _cchLength) noexcept + { + SetByteLength(Length + _cchLength * sizeof(wchar_t)); + } + }; + } + +} //namespace YY + +#include "ThreadRunner.h" + +#define _DEFINE_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE) _LCRT_DEFINE_IAT_SYMBOL(_PREFIX ## _FUNCTION, _SIZE) +#define _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE) _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL(_FUNCTION, _SIZE, _PREFIX ## _FUNCTION) + +//导入实际的实现 +#define YY_Thunks_Implemented +#define __DEFINE_THUNK_IMP_PREFIX(_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ + static decltype(_CRT_CONCATENATE_(_PREFIX, _FUNCTION))* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept \ + { \ + __CHECK_UNIT_TEST_BOOL(_FUNCTION); \ + __declspec(allocate(".YYThr$AAA")) static void* _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ + reinterpret_cast(&_CRT_CONCATENATE(try_get_, _FUNCTION)); \ + /*为了避免编译器将 YYThr$AAA 节优化掉*/ \ + __foreinclude(_CRT_CONCATENATE(pInit_ ,_FUNCTION)); \ + __declspec(allocate(".YYThu$AAB")) static void* _CRT_CONCATENATE(pFun_, _FUNCTION); \ + static const ProcInfo _ProcInfo = \ + { \ + _CRT_STRINGIZE(_FUNCTION), \ + &_CRT_CONCATENATE(try_get_module_, _MODULE), \ +__if_exists(YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION)) \ +{ \ + &YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION) \ +} \ + }; \ + return reinterpret_cast(try_get_function( \ + &_CRT_CONCATENATE(pFun_ ,_FUNCTION), \ + _ProcInfo)); \ + } \ + _DEFINE_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE); \ + _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL_PREFIX(_PREFIX, _FUNCTION, _SIZE); \ + EXTERN_C _RETURN_ _CONVENTION_ _CRT_CONCATENATE_(_PREFIX, _FUNCTION)(__VA_ARGS__) + +#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) __DEFINE_THUNK_IMP_PREFIX(__FALLBACK_PREFIX, _MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, __VA_ARGS__) + +#include "YY_Thunks_List.hpp" + +#undef __DEFINE_THUNK +#undef YY_Thunks_Implemented + +static HMODULE __fastcall try_get_module(volatile HMODULE* pModule, const wchar_t* module_name, int Flags) noexcept +{ + // First check to see if we've cached the module handle: + if (HMODULE const cached_handle = __crt_interlocked_read_pointer(pModule)) + { + if (cached_handle == INVALID_HANDLE_VALUE) + { + return nullptr; + } + + return cached_handle; + } + + // If we haven't yet cached the module handle, try to load the library. If + // this fails, cache the sentinel handle value INVALID_HANDLE_VALUE so that + // we don't attempt to load the module again: + HMODULE new_handle = NULL; + + if (__pfnYY_Thunks_CustomLoadLibrary) + { + new_handle = __pfnYY_Thunks_CustomLoadLibrary(module_name, Flags); + } + + if (new_handle) + { + // 使用 CustomLoadLibrary的结果 + if (new_handle == INVALID_HANDLE_VALUE) + new_handle = nullptr; + } + else if (Flags & USING_GET_MODULE_HANDLE) + { + new_handle = GetModuleHandleW(module_name); + } + else + { + // 我们不能直接使用 LoadLibraryExW,因为它可能被Thunk。 + __if_exists(YY::Thunks::try_get_LoadLibraryExW) + { + const auto LoadLibraryExW = YY::Thunks::try_get_LoadLibraryExW(); + if (!LoadLibraryExW) + return nullptr; + } + + if (Flags & LOAD_AS_DATA_FILE) + { + new_handle = LoadLibraryExW(module_name, NULL, LOAD_LIBRARY_AS_DATAFILE); + } + else if (Flags & USING_UNSAFE_LOAD) + { + new_handle = LoadLibraryExW(module_name, nullptr, 0); + } + else + { + // 使用DLL安全加载 +#if (YY_Thunks_Target < __WindowsNT6_2) + if (!try_get_AddDllDirectory()) + { +#if !defined(__USING_NTDLL_LIB) + const auto LdrLoadDll = try_get_LdrLoadDll(); + if (!LdrLoadDll) + return nullptr; +#endif + wchar_t szFilePathBuffer[MAX_PATH] = {}; + const auto _cchSystemPath = GetSystemDirectoryW(szFilePathBuffer, _countof(szFilePathBuffer)); + if (_cchSystemPath == 0 || _cchSystemPath >= _countof(szFilePathBuffer)) + { + // 回落普通加载,按理说 GetSystemDirectoryW不应该发生这样的失败。 + new_handle = LoadLibraryExW(module_name, nullptr, 0); + } + else + { + auto _sModuleName = YY::Thunks::internal::MakeNtString(module_name); + LdrLoadDll(szFilePathBuffer, nullptr, &_sModuleName, &new_handle); + } + } + else +#endif + { + new_handle = LoadLibraryExW(module_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + } + } + + if (!new_handle) + { + if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(pModule, INVALID_HANDLE_VALUE)) + { + _ASSERTE(cached_handle == INVALID_HANDLE_VALUE); + } + + return nullptr; + } + + // Swap the new handle into the cache. If the cache no longer contained a + // null handle, then some other thread loaded the module and cached the + // handle while we were doing the same. In that case, we free the handle + // once to maintain the reference count: + if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(pModule, new_handle)) + { + _ASSERTE(cached_handle == new_handle); + FreeLibrary(new_handle); + } + + return new_handle; +} + +static __forceinline void* __fastcall try_get_proc_address_from_dll( + const ProcInfo& _ProcInfo + ) noexcept +{ + HMODULE const module_handle = _ProcInfo.pfnGetModule(); + if (!module_handle) + { + return nullptr; + } + + // 无法直接调用GetProcAddress,因为GetProcAddress可能被Thunk + // 我们需要严格判断,避免发生死锁。 +#if defined(__USING_NTDLL_LIB) + void* _pProc = nullptr; + if (uintptr_t(_ProcInfo.szProcName) > UINT16_MAX) + { + ANSI_STRING _sFunctionName = YY::Thunks::internal::MakeNtString(_ProcInfo.szProcName); + LdrGetProcedureAddress(module_handle, &_sFunctionName, 0, &_pProc); + } + else + { + LdrGetProcedureAddress(module_handle, nullptr, (WORD)uintptr_t(_ProcInfo.szProcName), &_pProc); + } + return _pProc; +#else // !defined(__USING_NTDLL_LIB) + __if_exists(YY::Thunks::try_get_GetProcAddress) + { + const auto GetProcAddress = YY::Thunks::try_get_GetProcAddress(); + } + + return reinterpret_cast(GetProcAddress(module_handle, _ProcInfo.szProcName)); +#endif // defined(__USING_NTDLL_LIB) +} + +static __forceinline void* __fastcall try_get_proc_address_from_first_available_module( + const ProcInfo& _ProcInfo + ) noexcept +{ + if (_ProcInfo.pfnCustomGetProcAddress) + { + return _ProcInfo.pfnCustomGetProcAddress(_ProcInfo); + } + + return try_get_proc_address_from_dll(_ProcInfo); +} diff --git a/src/Thunks/api-ms-win-core-libraryloader.hpp b/src/Thunks/api-ms-win-core-libraryloader.hpp index 2a742b1..32b7bf8 100644 --- a/src/Thunks/api-ms-win-core-libraryloader.hpp +++ b/src/Thunks/api-ms-win-core-libraryloader.hpp @@ -1,1137 +1,1759 @@ - -#ifdef YY_Thunks_Implemented -namespace YY::Thunks::Fallback -{ - namespace - { -#if YY_Thunks_Target < __WindowsNT6_2 - static DWORD s_DirectoryFlags/* = 0*/; -#endif - - /*LSTATUS __fastcall BasepGetModuleHandleExParameterValidation( - _In_ DWORD dwFlags, - _In_opt_ LPCSTR lpModuleName, - _Out_ HMODULE* phModule - )*/ -#define BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule) \ - for (;;) \ - { \ - if (phModule) \ - { \ - *phModule = nullptr; \ - if ((dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) == 0 \ - || (dwFlags & (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) != (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) \ - || (lpModuleName || (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) == 0)) \ - { \ - if (lpModuleName == nullptr) \ - { \ - *phModule = (HMODULE)((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ImageBaseAddress; \ - return TRUE; \ - } \ - break; \ - } \ - } \ - SetLastError(ERROR_INVALID_PARAMETER); \ - return FALSE; \ - } - -#define __FORWARD_DLL_MODULE HMODULE(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ImageBaseAddress) - - template - HMODULE __fastcall ForwardDll(_In_z_ const Char* _szLibFileName) - { -#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (YY_Thunks_Target < __WindowsNT6_1) - if (_szLibFileName == nullptr || *_szLibFileName == L'\0') - return nullptr; - - auto _szFileName = _szLibFileName; - for (; *_szLibFileName; ) - { - if (*_szLibFileName == Char('\\') || *_szLibFileName == Char('/')) - { - ++_szLibFileName; - _szFileName = _szLibFileName; - } - else - { - ++_szLibFileName; - } - } - -#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (YY_Thunks_Target < __WindowsNT6_1) - if (internal::GetSystemVersion() < internal::MakeVersion(6, 1) - && StringCompareIgnoreCaseByAscii(_szFileName, L"bcryptprimitives", 16) == 0) - { - _szFileName += 16; - if (*_szFileName == L'\0' || StringCompareIgnoreCaseByAscii(_szFileName, ".dll", -1) == 0) - { - // Windows 7以下平台没有这个DLL,用进程模块句柄伪装一下。 - return __FORWARD_DLL_MODULE; - } - } -#endif -#endif - return nullptr; - } - -#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 - void* __fastcall try_get_GetProcAddress(const ProcInfo& _ProcInfo) - { - auto _hModule = _ProcInfo.pfnGetModule(); - if (!_hModule) - return nullptr; - -#if defined(__USING_NTDLL_LIB) - void* _pProc = nullptr; - ANSI_STRING _sFunctionName = YY::Thunks::internal::MakeNtString(_ProcInfo.szProcName); - const LONG _Status = LdrGetProcedureAddress(_hModule, &_sFunctionName, 0, &_pProc); - return _Status >= 0 ? _pProc : nullptr; -#else // !defined(__USING_NTDLL_LIB) - - // 防止遇到畸形的DLL,抓个异常 - __try - { - ULONG _uSize; - auto _pExport = (_IMAGE_EXPORT_DIRECTORY*)YY_ImageDirectoryEntryToData(_hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, &_uSize); - if (!_pExport) - return nullptr; - - if (_pExport->AddressOfNames == 0 || _pExport->AddressOfFunctions == 0 || _pExport->AddressOfNameOrdinals == 0) - return nullptr; - - auto _puFunctions = (const DWORD*)(PBYTE(_hModule) + _pExport->AddressOfFunctions); - auto _puNames = (const DWORD*)(PBYTE(_hModule) + _pExport->AddressOfNames); - auto _puNameOrdinals = (const WORD*)(PBYTE(_hModule) + _pExport->AddressOfNameOrdinals); - - for (DWORD i = 0; i != _pExport->NumberOfNames; ++i) - { - auto _uName = _puNames[i]; - if (_uName == 0) - continue; - - auto _szName = (char*)(PBYTE(_hModule) + _uName); - - if (StringCompare(_szName, _ProcInfo.szProcName, -1) == 0) - { - auto _pfn = PBYTE(_hModule) + _puFunctions[_puNameOrdinals[i]]; - return _pfn; - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } - return nullptr; -#endif // defined(__USING_NTDLL_LIB) - } -#endif - } -} -#endif - -namespace YY::Thunks -{ -#if (YY_Thunks_Target < __WindowsNT5_1) - - //Windows XP [desktop apps only] - //Windows Server 2003 [desktop apps only] - __DEFINE_THUNK( - kernel32, - 12, - BOOL, - WINAPI, - GetModuleHandleExA, - _In_ DWORD dwFlags, - _In_opt_ LPCSTR lpModuleName, - _Out_ HMODULE* phModule - ) - { - if (const auto pGetModuleHandleExA = try_get_GetModuleHandleExA()) - { - return pGetModuleHandleExA(dwFlags, lpModuleName, phModule); - } - - BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule); - - if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) - { - EnterCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); - } - - LSTATUS lStatus = ERROR_SUCCESS; - - for (;;) - { - HMODULE hModule; - - if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) - { -#if !defined(__USING_NTDLL_LIB) - const auto RtlPcToFileHeader = try_get_RtlPcToFileHeader(); - if (!RtlPcToFileHeader) - { - lStatus = ERROR_NOT_SUPPORTED; - break; - } -#endif - - hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName, (PVOID*)&hModule); - } - else - { - hModule = GetModuleHandleA(lpModuleName); - } - - if (hModule == nullptr) - { - lStatus = ERROR_DLL_NOT_FOUND; - break; - } - - if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) - { - - } - else - { -#if !defined(__USING_NTDLL_LIB) - const auto LdrAddRefDll = try_get_LdrAddRefDll(); - if (!LdrAddRefDll) - { - lStatus = ERROR_NOT_SUPPORTED; - break; - } -#endif - - LONG Status = LdrAddRefDll(dwFlags& GET_MODULE_HANDLE_EX_FLAG_PIN, hModule); - if (Status < 0) - { - lStatus = internal::BaseSetLastNTError(Status); - break; - } - } - - *phModule = hModule; - - break; - } - - if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) - { - LeaveCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); - } - - if (lStatus) - { - SetLastError(lStatus); - return FALSE; - } - else - { - return TRUE; - } - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT5_1) - - //Windows XP [desktop apps only] - //Windows Server 2003 [desktop apps only] - __DEFINE_THUNK( - kernel32, - 12, - BOOL, - WINAPI, - GetModuleHandleExW, - _In_ DWORD dwFlags, - _In_opt_ LPCWSTR lpModuleName, - _Out_ HMODULE* phModule - ) - { - if (const auto pGetModuleHandleExW = try_get_GetModuleHandleExW()) - { - return pGetModuleHandleExW(dwFlags, lpModuleName, phModule); - } - - BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule); - - if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) - { - EnterCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); - } - - LSTATUS lStatus = ERROR_SUCCESS; - - for (;;) - { - HMODULE hModule; - - if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) - { -#if !defined(__USING_NTDLL_LIB) - const auto RtlPcToFileHeader = try_get_RtlPcToFileHeader(); - if (!RtlPcToFileHeader) - { - lStatus = ERROR_NOT_SUPPORTED; - break; - } -#endif - - hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName, (PVOID*)&hModule); - } - else - { - hModule = GetModuleHandleW(lpModuleName); - } - - if (hModule == nullptr) - { - lStatus = ERROR_DLL_NOT_FOUND; - break; - } - - if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) - { - - } - else - { -#if !defined(__USING_NTDLL_LIB) - const auto LdrAddRefDll = try_get_LdrAddRefDll(); - if (!LdrAddRefDll) - { - lStatus = ERROR_NOT_SUPPORTED; - break; - } -#endif - - LONG Status = LdrAddRefDll(dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN, hModule); - if (Status < 0) - { - lStatus = internal::BaseSetLastNTError(Status); - break; - } - } - - *phModule = hModule; - - break; - } - - if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) - { - LeaveCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); - } - - if (lStatus) - { - SetLastError(lStatus); - return FALSE; - } - else - { - return TRUE; - } - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_2) - - //虽然这个早就有了,但是只有Windows 8以及打了KB2533623补丁的系统才支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等特性 - __DEFINE_THUNK( - kernel32, - 12, - _Ret_maybenull_ - HMODULE, - WINAPI, - LoadLibraryExW, - _In_ LPCWSTR lpLibFileName, - _Reserved_ HANDLE hFile, - _In_ DWORD dwFlags - ) - { - const auto pLoadLibraryExW = try_get_LoadLibraryExW(); - - if (!pLoadLibraryExW) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - - if (dwFlags == 0 || try_get_AddDllDirectory() != nullptr) - { - //存在AddDllDirectory说明支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等功能,直接调用pLoadLibraryExW即可。 - - auto _hModule = pLoadLibraryExW(lpLibFileName, hFile, dwFlags); - if (_hModule) - return _hModule; - - return Fallback::ForwardDll(lpLibFileName); - } - -#if (YY_Thunks_Target < __WindowsNT6) - //Windows Vista开始才支持 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE,对于不支持的系统我们只能Fallblack到 LOAD_LIBRARY_AS_DATAFILE - if (dwFlags & (LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)) - { - auto pPeb = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; - - if (pPeb->OSMajorVersion < 6) - { - dwFlags &= ~(LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); - dwFlags |= LOAD_LIBRARY_AS_DATAFILE; - } - } -#endif - wchar_t szFilePathBuffer[1024]; - - - - do - { - auto dwLoadLibrarySearchFlags = dwFlags & 0xFFFFFF00; - - if (dwLoadLibrarySearchFlags == 0) - { - break; - } - - if (((LOAD_WITH_ALTERED_SEARCH_PATH | 0xFFFFE000 | 0x00000004) & dwFlags) || lpLibFileName == nullptr || hFile) - { - //LOAD_WITH_ALTERED_SEARCH_PATH 标记不允许跟其他标记组合使用 - //0xFFFFE000 为 其他不支持的数值 - //LOAD_PACKAGED_LIBRARY: 0x00000004 Windows 8以上平台才支持 - SetLastError(ERROR_INVALID_PARAMETER); - return nullptr; - } - - dwFlags &= 0xFF; - - //LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 等价于 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS标记 - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) - dwLoadLibrarySearchFlags = (dwLoadLibrarySearchFlags & ~LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) | (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32); - - - - if (dwLoadLibrarySearchFlags == (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32)) - { - //如果确定是调用默认体系,则直接调用原始 LoadLibraryExW - - break; - } -#if defined(__USING_NTDLL_LIB) - const auto PathType = RtlDetermineDosPathNameType_U(lpLibFileName); -#else - const auto RtlDetermineDosPathNameType_U = try_get_RtlDetermineDosPathNameType_U(); - const auto PathType = RtlDetermineDosPathNameType_U ? RtlDetermineDosPathNameType_U(lpLibFileName) : RtlPathTypeUnknown; -#endif - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) - { - //必须是一个完整路径! - if (PathType == RtlPathTypeUnknown || PathType == RtlPathTypeDriveRelative || PathType == RtlPathTypeRelative) - { - SetLastError(ERROR_INVALID_PARAMETER); - return nullptr; - } - - if (dwLoadLibrarySearchFlags == (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32)) - { - //LOAD_WITH_ALTERED_SEARCH_PATH参数能模拟 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 组合效果。 - dwFlags |= LOAD_WITH_ALTERED_SEARCH_PATH; - break; - } - } - - - if (LOAD_LIBRARY_SEARCH_USER_DIRS & dwLoadLibrarySearchFlags) - { - //LOAD_LIBRARY_SEARCH_USER_DIRS 无法顺利实现,索性无效参数处理 - SetLastError(ERROR_INVALID_PARAMETER); - return nullptr; - } - - - - - if (dwFlags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) - { - //以资源方式加载 - - //判断路径是一个绝对路径还是一个相对路径,如果是绝对路径,那么可以直接无视 LOAD_LIBRARY_SEARCH_ 系列参数。 - if ((PathType == RtlPathTypeUnknown || PathType == RtlPathTypeDriveRelative || PathType == RtlPathTypeRelative) == false) - { - //是一个绝对路径,我们直接传递给 pLoadLibraryExW 即可 - - break; - } - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR) - { - auto nSize = GetModuleFileNameW(NULL, szFilePathBuffer, _countof(szFilePathBuffer)); - - if (nSize == 0 || nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - for (;;) - { - if (szFilePathBuffer[nSize] == L'\\' || szFilePathBuffer[nSize] == L'/') - { - ++nSize; - break; - } - - if (nSize == 0) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - --nSize; - } - - - for (auto Str = lpLibFileName; *Str; ++Str, ++nSize) - { - if (nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - szFilePathBuffer[nSize] = *Str; - } - - szFilePathBuffer[nSize] = L'\0'; - - - if (GetFileAttributesW(szFilePathBuffer) != -1) - { - lpLibFileName = szFilePathBuffer; - break; - } - } - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_SYSTEM32) - { - auto nSize = GetSystemDirectoryW(szFilePathBuffer, _countof(szFilePathBuffer)); - - if (nSize == 0 || nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - if (szFilePathBuffer[nSize] != L'\\') - { - if (nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - szFilePathBuffer[++nSize] = L'\\'; - } - - for (auto Str = lpLibFileName; *Str; ++Str, ++nSize) - { - if (nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - szFilePathBuffer[nSize] = *Str; - } - - szFilePathBuffer[nSize] = L'\0'; - - if (GetFileAttributesW(szFilePathBuffer) != -1) - { - lpLibFileName = szFilePathBuffer; - break; - } - } - - SetLastError(ERROR_MOD_NOT_FOUND); - return nullptr; - } - - - //以模块方式加载 -#if !defined(__USING_NTDLL_LIB) - const auto LdrLoadDll = try_get_LdrLoadDll(); - if (!LdrLoadDll) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } -#endif - - DWORD nSize = 0; - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) - { - for (auto Str = lpLibFileName; *Str; ++Str, ++nSize) - { - if (nSize >= _countof(szFilePathBuffer)) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - szFilePathBuffer[nSize] = *Str; - } - - if (nSize == 0) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - --nSize; - //反向剔除文件名 - for (;;) - { - if (szFilePathBuffer[nSize] == L'\\' || szFilePathBuffer[nSize] == L'/') - { - break; - } - - if (nSize == 0) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - --nSize; - } - - ++nSize; - szFilePathBuffer[nSize] = L';'; - ++nSize; - } - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR) - { - const DWORD nBufferMax = _countof(szFilePathBuffer) - nSize; - - auto nBuffer = GetModuleFileNameW(NULL, szFilePathBuffer + nSize, nBufferMax); - - if (nBuffer == 0 || nBuffer >= nBufferMax) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - nSize += nBuffer - 1; - - for (;;) - { - if (szFilePathBuffer[nSize] == L'\\' || szFilePathBuffer[nSize] == L'/') - { - break; - } - - if (nSize == 0) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - --nSize; - } - - ++nSize; - szFilePathBuffer[nSize] = L';'; - ++nSize; - } - - if (dwLoadLibrarySearchFlags & LOAD_LIBRARY_SEARCH_SYSTEM32) - { - const DWORD nBufferMax = _countof(szFilePathBuffer) - nSize; - - auto nBuffer = GetSystemDirectoryW(szFilePathBuffer + nSize, nBufferMax); - - if (nBuffer == 0 || nBuffer >= nBufferMax) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - nSize += nBuffer; - } - - szFilePathBuffer[nSize] = L'\0'; - - UNICODE_STRING ModuleFileName; - ModuleFileName.Buffer = (PWSTR)lpLibFileName; - - for (; *lpLibFileName; ++lpLibFileName); - const auto _uNewLength = (lpLibFileName - ModuleFileName.Buffer) * sizeof(lpLibFileName[0]); - if (_uNewLength + sizeof(lpLibFileName[0]) > MAXUINT16) - { - SetLastError(ERROR_INVALID_PARAMETER); - return nullptr; - } - - ModuleFileName.Length = static_cast(_uNewLength); - ModuleFileName.MaximumLength = ModuleFileName.Length + sizeof(lpLibFileName[0]); - - HMODULE hModule = NULL; - - ULONG dwLdrLoadDllFlags = 0; - - if (dwFlags & DONT_RESOLVE_DLL_REFERENCES) - { - dwLdrLoadDllFlags |= 0x2; - } - - if (dwFlags & LOAD_IGNORE_CODE_AUTHZ_LEVEL) - { - dwLdrLoadDllFlags |= 0x1000; - } - - if (dwFlags & LOAD_LIBRARY_REQUIRE_SIGNED_TARGET) - { - dwLdrLoadDllFlags |= 0x800000; - } - -#if defined(_M_IX86) && YY_Thunks_Target < __WindowsNT6_1_SP1 - //我们先关闭重定向,再加载DLL,Windows 7 SP1以前的系统不会关闭重定向,而导致某些线程关闭重定向后DLL加载问题。 - PVOID OldFsRedirectionLevel; - - auto pRtlWow64EnableFsRedirectionEx = try_get_RtlWow64EnableFsRedirectionEx(); - auto StatusFsRedir = pRtlWow64EnableFsRedirectionEx ? pRtlWow64EnableFsRedirectionEx(nullptr, &OldFsRedirectionLevel) : 0; -#endif - - LONG Status = LdrLoadDll(szFilePathBuffer, &dwLdrLoadDllFlags, &ModuleFileName, &hModule); - -#if defined(_M_IX86) && YY_Thunks_Target < __WindowsNT6_1_SP1 - if (StatusFsRedir >= 0 && pRtlWow64EnableFsRedirectionEx) - pRtlWow64EnableFsRedirectionEx(OldFsRedirectionLevel, &OldFsRedirectionLevel); -#endif - if (Status < 0) - { - YY::Thunks::internal::BaseSetLastNTError(Status); - } - - if (hModule) - return hModule; - - return Fallback::ForwardDll(lpLibFileName); - } while (false); - -#if defined(_M_IX86) && YY_Thunks_Target < __WindowsNT6_1_SP1 - //我们先关闭重定向,再加载DLL,Windows 7 SP1以前的系统不会关闭重定向,而导致某些线程关闭重定向后DLL加载问题。 - PVOID OldFsRedirectionLevel; - - auto pRtlWow64EnableFsRedirectionEx = try_get_RtlWow64EnableFsRedirectionEx(); - auto StatusFsRedir = pRtlWow64EnableFsRedirectionEx ? pRtlWow64EnableFsRedirectionEx(nullptr, &OldFsRedirectionLevel) : 0; -#endif - - auto hModule = pLoadLibraryExW(lpLibFileName, hFile, dwFlags); - -#if defined(_M_IX86) && YY_Thunks_Target < __WindowsNT6_1_SP1 - if (StatusFsRedir >= 0 && pRtlWow64EnableFsRedirectionEx) - { - LSTATUS lStatus = GetLastError(); - pRtlWow64EnableFsRedirectionEx(OldFsRedirectionLevel, &OldFsRedirectionLevel); - SetLastError(lStatus); - } -#endif - if(hModule) - return hModule; - - return Fallback::ForwardDll(lpLibFileName); - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_2) - - //虽然这个早就有了,但是只有Windows 8以及打了KB2533623补丁的系统才支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等特性 - __DEFINE_THUNK( - kernel32, - 12, - _Ret_maybenull_ - HMODULE, - WINAPI, - LoadLibraryExA, - _In_ LPCSTR lpLibFileName, - _Reserved_ HANDLE hFile, - _In_ DWORD dwFlags - ) - { - const auto pLoadLibraryExA = try_get_LoadLibraryExA(); - - if (!pLoadLibraryExA) - { - SetLastError(ERROR_FUNCTION_FAILED); - return nullptr; - } - - - if (dwFlags == 0 || try_get_AddDllDirectory() != nullptr) - { - //存在AddDllDirectory说明支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等功能,直接调用pLoadLibraryExW即可。 - - auto _hModule = pLoadLibraryExA(lpLibFileName, hFile, dwFlags); - if (_hModule) - return _hModule; - - return Fallback::ForwardDll(lpLibFileName); - } - - wchar_t szLibFileNameUnicode[512]; - - UNICODE_STRING usLibFileName = { 0, sizeof(szLibFileNameUnicode), szLibFileNameUnicode }; - - auto lStatus = internal::Basep8BitStringToStaticUnicodeString(&usLibFileName, lpLibFileName); - if (lStatus != ERROR_SUCCESS) - { - SetLastError(lStatus); - return nullptr; - } - - return LoadLibraryExW(szLibFileNameUnicode, hFile, dwFlags); - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6) - - // Windows Vista [仅限桌面应用], Windows Server 2008 [仅限桌面应用] - __DEFINE_THUNK( - kernel32, - 28, - BOOL, - APIENTRY, - EnumResourceLanguagesExW, - _In_opt_ HMODULE _hModule, - _In_ LPCWSTR _lpType, - _In_ LPCWSTR _lpName, - _In_ ENUMRESLANGPROCW _lpEnumFunc, - _In_opt_ LONG_PTR _lParam, - DWORD _dwFlags, - LANGID _LangId - ) - { - const auto _pfnEnumResourceLanguagesExW = try_get_EnumResourceLanguagesExW(); - - if (_pfnEnumResourceLanguagesExW) - { - return _pfnEnumResourceLanguagesExW(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam, _dwFlags, _LangId); - } - - // WinXP不支持MUI,故而忽略 _dwFlags、_LangId - return EnumResourceLanguagesW(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam); - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6) - - // Windows Vista [仅限桌面应用], Windows Server 2008 [仅限桌面应用] - __DEFINE_THUNK( - kernel32, - 28, - BOOL, - APIENTRY, - EnumResourceLanguagesExA, - _In_opt_ HMODULE _hModule, - _In_ LPCSTR _lpType, - _In_ LPCSTR _lpName, - _In_ ENUMRESLANGPROCA _lpEnumFunc, - _In_opt_ LONG_PTR _lParam, - DWORD _dwFlags, - LANGID _LangId - ) - { - const auto _pfnEnumResourceLanguagesExA = try_get_EnumResourceLanguagesExA(); - - if (_pfnEnumResourceLanguagesExA) - { - return _pfnEnumResourceLanguagesExA(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam, _dwFlags, _LangId); - } - - // WinXP不支持MUI,故而忽略 _dwFlags、_LangId - return EnumResourceLanguagesA(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam); - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_1) - - // 最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用] - // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] - __DEFINE_THUNK( - kernel32, - 24, - int, - WINAPI, - FindStringOrdinal, - _In_ DWORD _uFindStringOrdinalFlags, - _In_reads_(_cchSource) LPCWSTR _pStringSource, - _In_ int _cchSource, - _In_reads_(_cchValue) LPCWSTR _pStringValue, - _In_ int _cchValue, - _In_ BOOL _bIgnoreCase - ) - { - if (const auto _pfnFindStringOrdinal = try_get_FindStringOrdinal()) - { - return _pfnFindStringOrdinal(_uFindStringOrdinalFlags, _pStringSource, _cchSource, _pStringValue, _cchValue, _bIgnoreCase); - } - - SetLastError(ERROR_SUCCESS); - if (_pStringSource == nullptr || _cchSource < -1 || _pStringValue == nullptr || _cchValue < -1) - { - SetLastError(ERROR_INVALID_PARAMETER); - return -1; - } - - if (_cchSource == -1) - { - _cchSource = (int)wcslen(_pStringSource); - } - - if (_cchSource == 0) - { - return -1; - } - - if (_cchValue == -1) - { - _cchValue = (int)wcslen(_pStringValue); - } - - if (_cchValue == 0 || _cchValue > _cchSource) - { - return -1; - } - - switch (_uFindStringOrdinalFlags) - { - case 0: - case FIND_FROMSTART: - for (auto _pStart = _pStringSource; _cchValue <= _cchSource;++_pStart, --_cchSource) - { - if (CompareStringOrdinal(_pStart, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) - { - return static_cast(_pStart - _pStringSource); - } - } - return -1; - break; - case FIND_FROMEND: - for (auto _pStart = _pStringSource + _cchSource - _cchValue; _cchValue <= _cchSource; --_pStart, --_cchSource) - { - if (CompareStringOrdinal(_pStart, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) - { - return static_cast(_pStart - _pStringSource); - } - } - return -1; - break; - case FIND_STARTSWITH: - if (CompareStringOrdinal(_pStringSource, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) - { - return 0; - } - return -1; - break; - case FIND_ENDSWITH: - _cchSource -= _cchValue; - if (CompareStringOrdinal(_pStringSource + _cchSource, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) - { - return _cchSource; - } - return -1; - break; - default: - SetLastError(ERROR_INVALID_FLAGS); - return -1; - break; - } - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6) - - // 最低受支持的客户端 Windows XP [桌面应用 | UWP 应用] - // 最低受支持的服务器 Windows Server 2003[桌面应用 | UWP 应用] - __DEFINE_THUNK( - kernel32, - 4, - BOOL, - WINAPI, - DisableThreadLibraryCalls, - _In_ HMODULE _hLibModule - ) - { - // 虽然XP已经支持这个函数,但是Windows XP动态加载的DLL依靠的是DllMainCRTStartupForYY_Thunks通知做的。 - // 强制依赖于ThreadLibraryCalls,我们不能正真的禁用它。 - if (internal::g_TlsMode != internal::TlsMode::ByDllMainCRTStartupForYY_Thunks) - { - if (const auto _pfnDisableThreadLibraryCalls = try_get_DisableThreadLibraryCalls()) - { - return _pfnDisableThreadLibraryCalls(_hLibModule); - } - } - - return TRUE; - } -#endif - - -#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 - - // 所有系统都支持,但是这个函数的存在是为了能顺利取到 ProcessPrng,Windows 8开始原生支持ProcessPrng - __DEFINE_THUNK( - kernel32, - 8, - FARPROC, - WINAPI, - GetProcAddress, - _In_ HMODULE hModule, - _In_ LPCSTR lpProcName - ) - { -#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 - if (uintptr_t(lpProcName) > UINT16_MAX) - { - if (StringCompare(lpProcName, "ProcessPrng", -1) == 0) - { - if (hModule == __FORWARD_DLL_MODULE || hModule == try_get_module_bcryptprimitives()) - { - const auto _pfn = try_get_ProcessPrng(); - return reinterpret_cast(_pfn ? _pfn : &ProcessPrng); - } - } - } -#endif - const auto _pfnGetProcAddress = try_get_GetProcAddress(); - if (!_pfnGetProcAddress) - { - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - return _pfnGetProcAddress(hModule, lpProcName); - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_2) - - // 所有系统都支持,但是现在为了支持 SetDefaultDllDirectories就Thunk下 - __DEFINE_THUNK( - kernel32, - 4, - HMODULE, - WINAPI, - LoadLibraryW, - _In_ LPCWSTR _szLibFileName - ) - { - if (Fallback::s_DirectoryFlags == 0 || try_get_AddDllDirectory()) - { - const auto _pfnLoadLibraryW = try_get_LoadLibraryW(); - if (!_pfnLoadLibraryW) - { - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - auto _hModule = _pfnLoadLibraryW(_szLibFileName); - if (_hModule) - return _hModule; - - return Fallback::ForwardDll(_szLibFileName); - } - else - { - return LoadLibraryExW(_szLibFileName, NULL, Fallback::s_DirectoryFlags); - } - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_2) - - // 所有系统都支持,但是现在为了支持 SetDefaultDllDirectories - __DEFINE_THUNK( - kernel32, - 4, - HMODULE, - WINAPI, - LoadLibraryA, - _In_ LPCSTR _szLibFileName - ) - { - if (Fallback::s_DirectoryFlags == 0 || try_get_AddDllDirectory()) - { - const auto _pfnLoadLibraryA = try_get_LoadLibraryA(); - if (!_pfnLoadLibraryA) - { - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - auto _hModule = _pfnLoadLibraryA(_szLibFileName); - if (_hModule) - return _hModule; - - return Fallback::ForwardDll(_szLibFileName); - } - else - { - return LoadLibraryExA(_szLibFileName, NULL, Fallback::s_DirectoryFlags); - } - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT6_2) - - // 最低受支持的客户端 Windows 8 [仅限桌面应用],在 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008 上KB2533623 - // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] - __DEFINE_THUNK( - kernel32, - 4, - BOOL, - WINAPI, - SetDefaultDllDirectories, - _In_ DWORD _fDirectoryFlags - ) - { - if (const auto _pfnSetDefaultDllDirectories = try_get_SetDefaultDllDirectories()) - { - return _pfnSetDefaultDllDirectories(_fDirectoryFlags); - } - - if (_fDirectoryFlags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) - { - _fDirectoryFlags &= ~LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; - _fDirectoryFlags |= LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS; - } - - if (_fDirectoryFlags & ~(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - Fallback::s_DirectoryFlags = _fDirectoryFlags; - return TRUE; - } -#endif - -} +#if YY_Thunks_Target < __WindowsNT6_2 +#include +#endif + +#ifdef YY_Thunks_Implemented +namespace YY::Thunks::Fallback +{ + namespace + { +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + static SRWLOCK s_DllDirectoryLock; + static UNICODE_STRING s_sDllDirectory; + + static void __cdecl FreeDllDirectory() noexcept + { + internal::UnicodeStringFree(s_sDllDirectory); + } + + static BOOL WINAPI DownlevelSetDllDirectoryW( + _In_opt_ LPCWSTR _szPathName + ) + { + __declspec(allocate(".YYThr$AAB")) static void* s_FreeDllDirectoryData = reinterpret_cast(&Fallback::FreeDllDirectory); + + const auto _cchPathName = internal::StringLength(_szPathName); + + LSTATUS _lStatus = ERROR_SUCCESS; + ::AcquireSRWLockExclusive(&Fallback::s_DllDirectoryLock); + Fallback::s_sDllDirectory.Length = 0; + if (_cchPathName) + { + _lStatus = internal::UnicodeStringAppend(Fallback::s_sDllDirectory, _szPathName, _cchPathName); + } + ::ReleaseSRWLockExclusive(&Fallback::s_DllDirectoryLock); + + if (_lStatus) + { + SetLastError(_lStatus); + return FALSE; + } + + return TRUE; + } +#endif // (YY_Thunks_Target < __WindowsNT5_1_SP1) + +#if YY_Thunks_Target < __WindowsNT6_2 + static DWORD s_DirectoryFlags/* = 0*/; + static SRWLOCK s_DllDirectoryListLock; + + struct DllDirectoryListEntry : public ListEntryImpl + { + size_t cchPath = 0; + wchar_t szPath[0]; + }; + + static ListImpl s_DllDirectoryList; + + static void __cdecl FreeDllDirectoryList() noexcept + { + auto _pItem = s_DllDirectoryList.pFirst; + s_DllDirectoryList.pFirst = nullptr; + s_DllDirectoryList.pLast = nullptr; + + while (_pItem) + { + auto _pNext = _pItem->pNext; + internal::Free(_pNext); + _pItem = _pNext; + } + } +#endif + + /*LSTATUS __fastcall BasepGetModuleHandleExParameterValidation( + _In_ DWORD _fFlags, + _In_opt_ LPCSTR lpModuleName, + _Out_ HMODULE* phModule + )*/ +#define BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule) \ + for (;;) \ + { \ + if (phModule) \ + { \ + *phModule = nullptr; \ + if ((dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) == 0 \ + || (dwFlags & (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) != (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) \ + || (lpModuleName || (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) == 0)) \ + { \ + if (lpModuleName == nullptr) \ + { \ + *phModule = (HMODULE)((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ImageBaseAddress; \ + return TRUE; \ + } \ + break; \ + } \ + } \ + SetLastError(ERROR_INVALID_PARAMETER); \ + return FALSE; \ + } + +#define __FORWARD_DLL_MODULE HMODULE(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ImageBaseAddress) + + template + HMODULE __fastcall ForwardDll(_In_z_ const Char* _szLibFileName) + { +#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (YY_Thunks_Target < __WindowsNT6_1) + if (_szLibFileName == nullptr || *_szLibFileName == L'\0') + return nullptr; + + auto _szFileName = _szLibFileName; + for (; *_szLibFileName; ) + { + if (*_szLibFileName == Char('\\') || *_szLibFileName == Char('/')) + { + ++_szLibFileName; + _szFileName = _szLibFileName; + } + else + { + ++_szLibFileName; + } + } + +#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && (YY_Thunks_Target < __WindowsNT6_1) + if (internal::GetSystemVersion() < internal::MakeVersion(6, 1) + && StringCompareIgnoreCaseByAscii(_szFileName, L"bcryptprimitives", 16) == 0) + { + _szFileName += 16; + if (*_szFileName == L'\0' || StringCompareIgnoreCaseByAscii(_szFileName, ".dll", -1) == 0) + { + // Windows 7以下平台没有这个DLL,用进程模块句柄伪装一下。 + return __FORWARD_DLL_MODULE; + } + } +#endif +#endif + return nullptr; + } + +#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 + void* __fastcall try_get_GetProcAddress(const ProcInfo& _ProcInfo) + { + auto _hModule = _ProcInfo.pfnGetModule(); + if (!_hModule) + return nullptr; + +#if defined(__USING_NTDLL_LIB) + void* _pProc = nullptr; + ANSI_STRING _sFunctionName = YY::Thunks::internal::MakeNtString(_ProcInfo.szProcName); + const LONG _Status = LdrGetProcedureAddress(_hModule, &_sFunctionName, 0, &_pProc); + return _Status >= 0 ? _pProc : nullptr; +#else // !defined(__USING_NTDLL_LIB) + + // 防止遇到畸形的DLL,抓个异常 + __try + { + ULONG _uSize; + auto _pExport = (_IMAGE_EXPORT_DIRECTORY*)YY_ImageDirectoryEntryToData(_hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, &_uSize); + if (!_pExport) + return nullptr; + + if (_pExport->AddressOfNames == 0 || _pExport->AddressOfFunctions == 0 || _pExport->AddressOfNameOrdinals == 0) + return nullptr; + + auto _puFunctions = (const DWORD*)(PBYTE(_hModule) + _pExport->AddressOfFunctions); + auto _puNames = (const DWORD*)(PBYTE(_hModule) + _pExport->AddressOfNames); + auto _puNameOrdinals = (const WORD*)(PBYTE(_hModule) + _pExport->AddressOfNameOrdinals); + + for (DWORD i = 0; i != _pExport->NumberOfNames; ++i) + { + auto _uName = _puNames[i]; + if (_uName == 0) + continue; + + auto _szName = (char*)(PBYTE(_hModule) + _uName); + + if (StringCompare(_szName, _ProcInfo.szProcName, -1) == 0) + { + auto _pfn = PBYTE(_hModule) + _puFunctions[_puNameOrdinals[i]]; + return _pfn; + } + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + return nullptr; +#endif // defined(__USING_NTDLL_LIB) + } +#endif + } +} +#endif + +namespace YY::Thunks +{ +#if (YY_Thunks_Target < __WindowsNT5_1) + + //Windows XP [desktop apps only] + //Windows Server 2003 [desktop apps only] + __DEFINE_THUNK( + kernel32, + 12, + BOOL, + WINAPI, + GetModuleHandleExA, + _In_ DWORD dwFlags, + _In_opt_ LPCSTR lpModuleName, + _Out_ HMODULE* phModule + ) + { + if (const auto pGetModuleHandleExA = try_get_GetModuleHandleExA()) + { + return pGetModuleHandleExA(dwFlags, lpModuleName, phModule); + } + + BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule); + + if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) + { + EnterCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); + } + + LSTATUS lStatus = ERROR_SUCCESS; + + for (;;) + { + HMODULE hModule; + + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) + { +#if !defined(__USING_NTDLL_LIB) + const auto RtlPcToFileHeader = try_get_RtlPcToFileHeader(); + if (!RtlPcToFileHeader) + { + lStatus = ERROR_NOT_SUPPORTED; + break; + } +#endif + + hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName, (PVOID*)&hModule); + } + else + { + hModule = GetModuleHandleA(lpModuleName); + } + + if (hModule == nullptr) + { + lStatus = ERROR_DLL_NOT_FOUND; + break; + } + + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) + { + + } + else + { +#if !defined(__USING_NTDLL_LIB) + const auto LdrAddRefDll = try_get_LdrAddRefDll(); + if (!LdrAddRefDll) + { + lStatus = ERROR_NOT_SUPPORTED; + break; + } +#endif + + LONG Status = LdrAddRefDll(dwFlags& GET_MODULE_HANDLE_EX_FLAG_PIN, hModule); + if (Status < 0) + { + lStatus = internal::BaseSetLastNTError(Status); + break; + } + } + + *phModule = hModule; + + break; + } + + if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) + { + LeaveCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); + } + + if (lStatus) + { + SetLastError(lStatus); + return FALSE; + } + else + { + return TRUE; + } + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT5_1) + + //Windows XP [desktop apps only] + //Windows Server 2003 [desktop apps only] + __DEFINE_THUNK( + kernel32, + 12, + BOOL, + WINAPI, + GetModuleHandleExW, + _In_ DWORD dwFlags, + _In_opt_ LPCWSTR lpModuleName, + _Out_ HMODULE* phModule + ) + { + if (const auto pGetModuleHandleExW = try_get_GetModuleHandleExW()) + { + return pGetModuleHandleExW(dwFlags, lpModuleName, phModule); + } + + BasepGetModuleHandleExParameterValidation(dwFlags, lpModuleName, phModule); + + if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) + { + EnterCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); + } + + LSTATUS lStatus = ERROR_SUCCESS; + + for (;;) + { + HMODULE hModule; + + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) + { +#if !defined(__USING_NTDLL_LIB) + const auto RtlPcToFileHeader = try_get_RtlPcToFileHeader(); + if (!RtlPcToFileHeader) + { + lStatus = ERROR_NOT_SUPPORTED; + break; + } +#endif + + hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName, (PVOID*)&hModule); + } + else + { + hModule = GetModuleHandleW(lpModuleName); + } + + if (hModule == nullptr) + { + lStatus = ERROR_DLL_NOT_FOUND; + break; + } + + if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) + { + + } + else + { +#if !defined(__USING_NTDLL_LIB) + const auto LdrAddRefDll = try_get_LdrAddRefDll(); + if (!LdrAddRefDll) + { + lStatus = ERROR_NOT_SUPPORTED; + break; + } +#endif + + LONG Status = LdrAddRefDll(dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN, hModule); + if (Status < 0) + { + lStatus = internal::BaseSetLastNTError(Status); + break; + } + } + + *phModule = hModule; + + break; + } + + if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) + { + LeaveCriticalSection(((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->LoaderLock); + } + + if (lStatus) + { + SetLastError(lStatus); + return FALSE; + } + else + { + return TRUE; + } + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + //虽然这个早就有了,但是只有Windows 8以及打了KB2533623补丁的系统才支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等特性 + __DEFINE_THUNK( + kernel32, + 12, + _Ret_maybenull_ + HMODULE, + WINAPI, + LoadLibraryExW, + _In_ LPCWSTR _szLibFileName, + _Reserved_ HANDLE _hFile, + _In_ DWORD _fFlags + ) + { + const auto _pfnLoadLibraryExW = try_get_LoadLibraryExW(); + if (!_pfnLoadLibraryExW) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + if (try_get_AddDllDirectory()) + { + //存在AddDllDirectory说明支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等功能,直接调用_pfnLoadLibraryExW即可。 + auto _hModule = _pfnLoadLibraryExW(_szLibFileName, _hFile, _fFlags); + if (_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } + + if (((LOAD_WITH_ALTERED_SEARCH_PATH | 0xFFFFE000 | 0x00000004) & _fFlags) || _szLibFileName == nullptr || _hFile) + { + //LOAD_WITH_ALTERED_SEARCH_PATH 标记不允许跟其他标记组合使用 + //0xFFFFE000 为 其他不支持的数值 + //LOAD_PACKAGED_LIBRARY: 0x00000004 Windows 8以上平台才支持 + SetLastError(ERROR_INVALID_PARAMETER); + return nullptr; + } + +#if (YY_Thunks_Target < __WindowsNT6) + //Windows Vista开始才支持 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE,对于不支持的系统我们只能Fallblack到 LOAD_LIBRARY_AS_DATAFILE + if (_fFlags & (LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)) + { + auto pPeb = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; + + if (pPeb->OSMajorVersion < 6) + { + _fFlags &= ~(LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + _fFlags |= LOAD_LIBRARY_AS_DATAFILE; + } + } +#endif + + constexpr DWORD kLoadLibrarySearchMarks = 0xFFFFFF00ul; + + // 检测是否包含 LOAD_LIBRARY_SEARCH_* | LOAD_WITH_ALTERED_SEARCH_PATH + // * 已包含 LOAD_LIBRARY_SEARCH_* 说明用户自行指定了这个参数,因此无需附加 s_DirectoryFlags + // * LOAD_WITH_ALTERED_SEARCH_PATH与所有 LOAD_LIBRARY_SEARCH_* 互斥,因此无需附加 s_DirectoryFlags + if ((_fFlags & (kLoadLibrarySearchMarks | LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) + { + _fFlags |= Fallback::s_DirectoryFlags; + } + +#if defined(_M_IX86) && YY_Thunks_Target < __WindowsNT6_1_SP1 + //我们先关闭重定向,再加载DLL,Windows 7 SP1以前的系统不会关闭重定向,而导致某些线程关闭重定向后DLL加载问题。 + class LoadDllEnalbeFsRedirection + { + PVOID OldFsRedirectionLevel = nullptr; + decltype(RtlWow64EnableFsRedirectionEx)* pfnRtlWow64EnableFsRedirectionEx = nullptr; + LONG Status = STATUS_NOINTERFACE; + + public: + LoadDllEnalbeFsRedirection() + { + pfnRtlWow64EnableFsRedirectionEx = try_get_RtlWow64EnableFsRedirectionEx(); + if (pfnRtlWow64EnableFsRedirectionEx) + { + Status = pfnRtlWow64EnableFsRedirectionEx(nullptr, &OldFsRedirectionLevel); + } + } + + ~LoadDllEnalbeFsRedirection() + { + if (Status >= 0 && pfnRtlWow64EnableFsRedirectionEx) + { + pfnRtlWow64EnableFsRedirectionEx(OldFsRedirectionLevel, &OldFsRedirectionLevel); + } + } + }; + + LoadDllEnalbeFsRedirection _AutoEnalbeFsRedirection; +#endif + + internal::UnicodeStringBuffer<1024> _szFilePathBuffer; + + do + { + // 为了偷懒同时照顾到安全性,模拟时我们始终采用安全搜索。 + // 搜索顺序参考:https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order + const auto _fOriginalFlags = _fFlags; + _fFlags &= ~kLoadLibrarySearchMarks; + + // 未使用任何扩展能力,这时可直接回退到系统 LoadLibraryExW + if ((_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + // 不支持 GetDllDirectoryW时后续任然需要模拟 + // 这是因为GetDllDirectoryW的路径在默认搜索列表中。 + if (try_get_GetDllDirectoryW() || Fallback::s_sDllDirectory.Length == 0) +#endif + { + break; + } + } + +#if defined(__USING_NTDLL_LIB) + const auto _ePathType = RtlDetermineDosPathNameType_U(_szLibFileName); +#else + const auto RtlDetermineDosPathNameType_U = try_get_RtlDetermineDosPathNameType_U(); + const auto _ePathType = RtlDetermineDosPathNameType_U ? RtlDetermineDosPathNameType_U(_szLibFileName) : RtlPathTypeUnknown; +#endif + + if (_fOriginalFlags & (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_WITH_ALTERED_SEARCH_PATH)) + { + //必须是一个完整路径! + if (_ePathType == RtlPathTypeUnknown || _ePathType == RtlPathTypeDriveRelative || _ePathType == RtlPathTypeRelative) + { + SetLastError(ERROR_INVALID_PARAMETER); + return nullptr; + } + } + + if (_fOriginalFlags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) + { + //以资源方式加载 + + //判断路径是一个绝对路径还是一个相对路径,如果是绝对路径,那么可以直接无视 LOAD_LIBRARY_SEARCH_ 系列参数。 + if ((_ePathType == RtlPathTypeUnknown || _ePathType == RtlPathTypeDriveRelative || _ePathType == RtlPathTypeRelative) == false) + { + // 是一个绝对路径,我们直接传递给 _pfnLoadLibraryExW 即可 + break; + } + + // 应用程序路径 + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / sizeof(wchar_t); + auto _cchFilePath = GetModuleFileNameW(NULL, _szFilePathBuffer.Buffer, kcchMaxBuffer); + + if (_cchFilePath == 0 || _cchFilePath >= kcchMaxBuffer) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + const auto _sAppDir = internal::UnicodeStringGetDir(_szFilePathBuffer.Buffer, _cchFilePath); + if(_sAppDir.Length == 0) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + _szFilePathBuffer.SetByteLength(_sAppDir.Length); + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + + // AddDllDirectory + if (_fOriginalFlags & (LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + { + LSTATUS _lStatus = ERROR_SUCCESS; + HMODULE _hModule = nullptr; + + ::AcquireSRWLockShared(&Fallback::s_DllDirectoryListLock); + for (auto _pItem = Fallback::s_DllDirectoryList.pFirst; _pItem; _pItem= _pItem->pNext) + { + if (_pItem->cchPath == 0) + continue; + + _szFilePathBuffer.Empty(); + if (_szFilePathBuffer.Append(_pItem->szPath, _pItem->cchPath)) + { + _lStatus = ERROR_NOT_ENOUGH_MEMORY; + break; + } + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + _lStatus = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + _lStatus = GetLastError(); + if (_hModule || _lStatus != ERROR_FILE_NOT_FOUND) + { + break; + } + } + ::ReleaseSRWLockShared(&Fallback::s_DllDirectoryListLock); + + if (_hModule) + { + return _hModule; + } + else if(_lStatus != ERROR_FILE_NOT_FOUND) + { + SetLastError(_lStatus); + return nullptr; + } + } + + // SetDllDirectory + bool _bHasDllDirectory = false; + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / sizeof(wchar_t); + const auto _cchBuffer = GetDllDirectoryW(kcchMaxBuffer, _szFilePathBuffer.Buffer); + if (_cchBuffer && _cchBuffer < kcchMaxBuffer) + { + _bHasDllDirectory = true; + _szFilePathBuffer.SetLength(_cchBuffer); + if (_szFilePathBuffer.Append(_szLibFileName)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + } + + // C:\\Windows\\System32 + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / 2; + auto _cchFilePath = GetSystemDirectoryW(_szFilePathBuffer.Buffer, kcchMaxBuffer); + + if (_cchFilePath == 0 || _cchFilePath >= kcchMaxBuffer) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetLength(_cchFilePath); + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + + if ((_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + // 16位系统文件夹 C:\\Windows\\System + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / 2; + auto _cchFilePath = GetWindowsDirectoryW(_szFilePathBuffer.Buffer, kcchMaxBuffer); + if (_cchFilePath == 0 || _cchFilePath >= kcchMaxBuffer) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetLength(_cchFilePath); + if (_szFilePathBuffer.AppendPath(L"System")) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + + // Windows文件夹 C:\\Windows + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / sizeof(wchar_t); + auto _cchFilePath = GetWindowsDirectoryW(_szFilePathBuffer.Buffer, kcchMaxBuffer); + if (_cchFilePath == 0 || _cchFilePath >= kcchMaxBuffer) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetLength(_cchFilePath); + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + + // 当前目录,注意设置 SetDllDirectory后,当前目录不生效。 + if (!_bHasDllDirectory) + { + const auto kcchMaxBuffer = _szFilePathBuffer.MaximumLength / sizeof(wchar_t); + auto _cchFilePath = GetCurrentDirectoryW(kcchMaxBuffer, _szFilePathBuffer.Buffer); + if (_cchFilePath == 0 || _cchFilePath >= kcchMaxBuffer) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetLength(_cchFilePath); + if (_szFilePathBuffer.AppendPath(_szLibFileName)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryExW(_szFilePathBuffer.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + + // %PATH% + { + auto _cchBuffer = ExpandEnvironmentStringsW(L"%PATH%", nullptr, 0); + for (; _cchBuffer;) + { + auto _szBuffer = _szFilePathBuffer.GetBuffer(_cchBuffer); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + const auto _cchResult = ExpandEnvironmentStringsW(L"%PATH%", _szBuffer, _cchBuffer); + if (_cchResult == 0) + break; + + if (_cchResult <= _cchBuffer) + { + _szFilePathBuffer.SetLength(_cchResult); + + internal::UnicodeStringBuffer _szTempPath; + const auto _pBufferEnd = _szBuffer + _cchResult; + for (;;) + { + auto _sItem = internal::UnicodeStringGetItem(_szBuffer, _pBufferEnd); + if (_sItem.MaximumLength == 0) + break; + + (LPBYTE&)_szBuffer += _sItem.Length; + if (_sItem.Length == 0) + continue; + + _szTempPath.Empty(); + if (_szTempPath.Append(_sItem) == ERROR_SUCCESS + && _szTempPath.AppendPath(_szLibFileName) == ERROR_SUCCESS) + { + auto _hModule = _pfnLoadLibraryExW(_szTempPath.Buffer, _hFile, _fFlags); + if (_hModule || GetLastError() != ERROR_FILE_NOT_FOUND) + { + return _hModule; + } + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + break; + } + + _cchBuffer = _cchResult; + } + } + } + + SetLastError(ERROR_MOD_NOT_FOUND); + return nullptr; + } + + //以模块方式加载 +#if !defined(__USING_NTDLL_LIB) + const auto LdrLoadDll = try_get_LdrLoadDll(); + if (!LdrLoadDll) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } +#endif + // DLL所在目录 + if (_fOriginalFlags & (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_WITH_ALTERED_SEARCH_PATH)) + { + const auto _sDllDir = internal::UnicodeStringGetDir(_szLibFileName, internal::StringLength(_szLibFileName)); + if (_sDllDir.Length == 0) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + if (_szFilePathBuffer.Append(_sDllDir)) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // 应用程序根目录 + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + auto _cchBuffer = GetModuleFileNameW(NULL, _szBuffer, MAX_PATH); + if (_cchBuffer == 0 || _cchBuffer >= MAX_PATH) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + const auto _sAppDir = internal::UnicodeStringGetDir(_szBuffer, _cchBuffer); + if (_sAppDir.Length == 0) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + _szFilePathBuffer.SetAppendByteLength(_sAppDir.Length); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // AddDllDirectory + if (_fOriginalFlags & (LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + { + ::AcquireSRWLockShared(&Fallback::s_DllDirectoryListLock); + LSTATUS _lStatus = ERROR_SUCCESS; + for (auto _pItem = Fallback::s_DllDirectoryList.pFirst; _pItem; _pItem = _pItem->pNext) + { + if (_pItem->cchPath == 0) + continue; + + _lStatus = _szFilePathBuffer.Append(_pItem->szPath, _pItem->cchPath); + if (_lStatus) + break; + + _lStatus = _szFilePathBuffer.Append(L';'); + if (_lStatus) + break; + } + ::ReleaseSRWLockShared(&Fallback::s_DllDirectoryListLock); + if(_lStatus) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // SetDllDirectoryW + bool _bHasDllDirectory = false; + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _cchBuffer = GetDllDirectoryW(MAX_PATH, _szBuffer); + if (_cchBuffer && _cchBuffer < MAX_PATH) + { + _bHasDllDirectory = true; + _szFilePathBuffer.SetAppendLength(_cchBuffer); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + } + + // System32 + if ((_fOriginalFlags & (LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + || (_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + auto _cchBuffer = GetSystemDirectoryW(_szBuffer, MAX_PATH); + if (_cchBuffer == 0 || _cchBuffer >= MAX_PATH) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetAppendLength(_cchBuffer); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + if ((_fOriginalFlags & kLoadLibrarySearchMarks) == 0) + { + // 16位系统文件夹 C:\\Windows\\System + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _cchBuffer = GetWindowsDirectoryW(_szBuffer, MAX_PATH); + if (_cchBuffer == 0 || _cchBuffer >= MAX_PATH) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetAppendLength(_cchBuffer); + if (_szFilePathBuffer.AppendPath(L"System")) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // Windows文件夹 C:\\Windows + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _cchBuffer = GetWindowsDirectoryW(_szBuffer, MAX_PATH); + if (_cchBuffer == 0 || _cchBuffer >= MAX_PATH) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetAppendLength(_cchBuffer); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // 当前目录,注意设置 SetDllDirectory后,当前目录不生效。 + if (!_bHasDllDirectory) + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(MAX_PATH); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + auto _cchBuffer = GetCurrentDirectoryW(MAX_PATH, _szBuffer); + if (_cchBuffer == 0 || _cchBuffer >= MAX_PATH) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + _szFilePathBuffer.SetAppendLength(_cchBuffer); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + } + + // %PATH% + { + + auto _cchBuffer = ExpandEnvironmentStringsW(L"%PATH%", nullptr, 0); + for (; _cchBuffer;) + { + auto _szBuffer = _szFilePathBuffer.GetAppendBuffer(_cchBuffer); + if (!_szBuffer) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + + const auto _cchResult = ExpandEnvironmentStringsW(L"%PATH%", _szBuffer, _cchBuffer); + if (_cchResult == 0) + break; + + if (_cchResult <= _cchBuffer) + { + _szFilePathBuffer.SetAppendLength(_cchResult); + if (_szFilePathBuffer.Append(L';')) + { + SetLastError(ERROR_OUTOFMEMORY); + return nullptr; + } + break; + } + + _cchBuffer = _cchResult; + } + } + } +#endif + + UNICODE_STRING _sModuleFileName = internal::MakeNtString(_szLibFileName); + HMODULE _hModule = NULL; + + ULONG dwLdrLoadDllFlags = 0; + + if (_fFlags & DONT_RESOLVE_DLL_REFERENCES) + { + dwLdrLoadDllFlags |= 0x2; + } + + if (_fFlags & LOAD_IGNORE_CODE_AUTHZ_LEVEL) + { + dwLdrLoadDllFlags |= 0x1000; + } + + if (_fFlags & LOAD_LIBRARY_REQUIRE_SIGNED_TARGET) + { + dwLdrLoadDllFlags |= 0x800000; + } + + LONG Status = LdrLoadDll(_szFilePathBuffer.Buffer, &dwLdrLoadDllFlags, &_sModuleFileName, &_hModule); + if (Status < 0) + { + YY::Thunks::internal::BaseSetLastNTError(Status); + } + + if (_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } while (false); + + auto _hModule = _pfnLoadLibraryExW(_szLibFileName, _hFile, _fFlags); + if(_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + //虽然这个早就有了,但是只有Windows 8以及打了KB2533623补丁的系统才支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等特性 + __DEFINE_THUNK( + kernel32, + 12, + _Ret_maybenull_ + HMODULE, + WINAPI, + LoadLibraryExA, + _In_ LPCSTR _szLibFileName, + _Reserved_ HANDLE _hFile, + _In_ DWORD _fFlags + ) + { + const auto _pfnLoadLibraryExA = try_get_LoadLibraryExA(); + if (!_pfnLoadLibraryExA) + { + SetLastError(ERROR_FUNCTION_FAILED); + return nullptr; + } + + if (try_get_AddDllDirectory()) + { + //存在AddDllDirectory说明支持 LOAD_LIBRARY_SEARCH_SYSTEM32 等功能,直接调用pLoadLibraryExW即可。 + + auto _hModule = _pfnLoadLibraryExA(_szLibFileName, _hFile, _fFlags); + if (_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } + + wchar_t _szLibFileNameUnicode[512]; + UNICODE_STRING _sLibFileName = { 0, sizeof(_szLibFileNameUnicode), _szLibFileNameUnicode }; + auto _lStatus = internal::Basep8BitStringToStaticUnicodeString(&_sLibFileName, _szLibFileName); + if (_lStatus != ERROR_SUCCESS) + { + SetLastError(_lStatus); + return nullptr; + } + + return LoadLibraryExW(_szLibFileNameUnicode, _hFile, _fFlags); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6) + + // Windows Vista [仅限桌面应用], Windows Server 2008 [仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 28, + BOOL, + APIENTRY, + EnumResourceLanguagesExW, + _In_opt_ HMODULE _hModule, + _In_ LPCWSTR _lpType, + _In_ LPCWSTR _lpName, + _In_ ENUMRESLANGPROCW _lpEnumFunc, + _In_opt_ LONG_PTR _lParam, + DWORD _dwFlags, + LANGID _LangId + ) + { + const auto _pfnEnumResourceLanguagesExW = try_get_EnumResourceLanguagesExW(); + + if (_pfnEnumResourceLanguagesExW) + { + return _pfnEnumResourceLanguagesExW(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam, _dwFlags, _LangId); + } + + // WinXP不支持MUI,故而忽略 _dwFlags、_LangId + return EnumResourceLanguagesW(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6) + + // Windows Vista [仅限桌面应用], Windows Server 2008 [仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 28, + BOOL, + APIENTRY, + EnumResourceLanguagesExA, + _In_opt_ HMODULE _hModule, + _In_ LPCSTR _lpType, + _In_ LPCSTR _lpName, + _In_ ENUMRESLANGPROCA _lpEnumFunc, + _In_opt_ LONG_PTR _lParam, + DWORD _dwFlags, + LANGID _LangId + ) + { + const auto _pfnEnumResourceLanguagesExA = try_get_EnumResourceLanguagesExA(); + + if (_pfnEnumResourceLanguagesExA) + { + return _pfnEnumResourceLanguagesExA(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam, _dwFlags, _LangId); + } + + // WinXP不支持MUI,故而忽略 _dwFlags、_LangId + return EnumResourceLanguagesA(_hModule, _lpType, _lpName, _lpEnumFunc, _lParam); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_1) + + // 最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用] + // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 24, + int, + WINAPI, + FindStringOrdinal, + _In_ DWORD _uFindStringOrdinalFlags, + _In_reads_(_cchSource) LPCWSTR _pStringSource, + _In_ int _cchSource, + _In_reads_(_cchValue) LPCWSTR _pStringValue, + _In_ int _cchValue, + _In_ BOOL _bIgnoreCase + ) + { + if (const auto _pfnFindStringOrdinal = try_get_FindStringOrdinal()) + { + return _pfnFindStringOrdinal(_uFindStringOrdinalFlags, _pStringSource, _cchSource, _pStringValue, _cchValue, _bIgnoreCase); + } + + SetLastError(ERROR_SUCCESS); + if (_pStringSource == nullptr || _cchSource < -1 || _pStringValue == nullptr || _cchValue < -1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + if (_cchSource == -1) + { + _cchSource = (int)wcslen(_pStringSource); + } + + if (_cchSource == 0) + { + return -1; + } + + if (_cchValue == -1) + { + _cchValue = (int)wcslen(_pStringValue); + } + + if (_cchValue == 0 || _cchValue > _cchSource) + { + return -1; + } + + switch (_uFindStringOrdinalFlags) + { + case 0: + case FIND_FROMSTART: + for (auto _pStart = _pStringSource; _cchValue <= _cchSource;++_pStart, --_cchSource) + { + if (CompareStringOrdinal(_pStart, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) + { + return static_cast(_pStart - _pStringSource); + } + } + return -1; + break; + case FIND_FROMEND: + for (auto _pStart = _pStringSource + _cchSource - _cchValue; _cchValue <= _cchSource; --_pStart, --_cchSource) + { + if (CompareStringOrdinal(_pStart, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) + { + return static_cast(_pStart - _pStringSource); + } + } + return -1; + break; + case FIND_STARTSWITH: + if (CompareStringOrdinal(_pStringSource, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) + { + return 0; + } + return -1; + break; + case FIND_ENDSWITH: + _cchSource -= _cchValue; + if (CompareStringOrdinal(_pStringSource + _cchSource, _cchValue, _pStringValue, _cchValue, _bIgnoreCase) == CSTR_EQUAL) + { + return _cchSource; + } + return -1; + break; + default: + SetLastError(ERROR_INVALID_FLAGS); + return -1; + break; + } + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6) + + // 最低受支持的客户端 Windows XP [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2003[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + DisableThreadLibraryCalls, + _In_ HMODULE _hLibModule + ) + { + // 虽然XP已经支持这个函数,但是Windows XP动态加载的DLL依靠的是DllMainCRTStartupForYY_Thunks通知做的。 + // 强制依赖于ThreadLibraryCalls,我们不能正真的禁用它。 + if (internal::g_TlsMode != internal::TlsMode::ByDllMainCRTStartupForYY_Thunks) + { + if (const auto _pfnDisableThreadLibraryCalls = try_get_DisableThreadLibraryCalls()) + { + return _pfnDisableThreadLibraryCalls(_hLibModule); + } + } + + return TRUE; + } +#endif + + +#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 + + // 所有系统都支持,但是这个函数的存在是为了能顺利取到 ProcessPrng,Windows 8开始原生支持ProcessPrng + __DEFINE_THUNK( + kernel32, + 8, + FARPROC, + WINAPI, + GetProcAddress, + _In_ HMODULE hModule, + _In_ LPCSTR lpProcName + ) + { +#if defined(__ENABLE_WORKAROUND_1_GetProcAddress_ProcessPrng) && YY_Thunks_Target < __WindowsNT6_2 + if (uintptr_t(lpProcName) > UINT16_MAX) + { + if (StringCompare(lpProcName, "ProcessPrng", -1) == 0) + { + if (hModule == __FORWARD_DLL_MODULE || hModule == try_get_module_bcryptprimitives()) + { + const auto _pfn = try_get_ProcessPrng(); + return reinterpret_cast(_pfn ? _pfn : &ProcessPrng); + } + } + } +#endif + const auto _pfnGetProcAddress = try_get_GetProcAddress(); + if (!_pfnGetProcAddress) + { + SetLastError(ERROR_PROC_NOT_FOUND); + return nullptr; + } + + return _pfnGetProcAddress(hModule, lpProcName); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + // 所有系统都支持,但是现在为了支持 SetDefaultDllDirectories就Thunk下 + __DEFINE_THUNK( + kernel32, + 4, + HMODULE, + WINAPI, + LoadLibraryW, + _In_ LPCWSTR _szLibFileName + ) + { + if (try_get_AddDllDirectory()) + { + const auto _pfnLoadLibraryW = try_get_LoadLibraryW(); + if (!_pfnLoadLibraryW) + { + SetLastError(ERROR_PROC_NOT_FOUND); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryW(_szLibFileName); + if (_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } + else + { + return LoadLibraryExW(_szLibFileName, NULL, 0); + } + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + // 所有系统都支持,但是现在为了支持 SetDefaultDllDirectories + __DEFINE_THUNK( + kernel32, + 4, + HMODULE, + WINAPI, + LoadLibraryA, + _In_ LPCSTR _szLibFileName + ) + { + if (try_get_AddDllDirectory()) + { + const auto _pfnLoadLibraryA = try_get_LoadLibraryA(); + if (!_pfnLoadLibraryA) + { + SetLastError(ERROR_PROC_NOT_FOUND); + return nullptr; + } + + auto _hModule = _pfnLoadLibraryA(_szLibFileName); + if (_hModule) + return _hModule; + + return Fallback::ForwardDll(_szLibFileName); + } + else + { + wchar_t _szLibFileNameUnicode[512]; + UNICODE_STRING _sLibFileName = { 0, sizeof(_szLibFileNameUnicode), _szLibFileNameUnicode }; + auto _lStatus = internal::Basep8BitStringToStaticUnicodeString(&_sLibFileName, _szLibFileName); + if (_lStatus != ERROR_SUCCESS) + { + SetLastError(_lStatus); + return nullptr; + } + + return LoadLibraryExW(_szLibFileNameUnicode, NULL, 0); + } + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用],在 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008 上KB2533623 + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + SetDefaultDllDirectories, + _In_ DWORD _fDirectoryFlags + ) + { + if (const auto _pfnSetDefaultDllDirectories = try_get_SetDefaultDllDirectories()) + { + return _pfnSetDefaultDllDirectories(_fDirectoryFlags); + } + + if (_fDirectoryFlags & ~(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + Fallback::s_DirectoryFlags = _fDirectoryFlags; + return TRUE; + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用],在 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008 上KB2533623 + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 4, + DLL_DIRECTORY_COOKIE, + WINAPI, + AddDllDirectory, + _In_ PCWSTR _szNewDirectory + ) + { + if (const auto _pfnAddDllDirectory = try_get_AddDllDirectory()) + { + return _pfnAddDllDirectory(_szNewDirectory); + } + + __declspec(allocate(".YYThr$AAB")) static void* s_FreeDllDirectoryListData = reinterpret_cast(&Fallback::FreeDllDirectoryList); + + LSTATUS _lStatus = ERROR_SUCCESS; + do + { +#if !defined(__USING_NTDLL_LIB) + const auto RtlDetermineDosPathNameType_U = try_get_RtlDetermineDosPathNameType_U(); + if (!RtlDetermineDosPathNameType_U) + { + _lStatus = ERROR_FUNCTION_FAILED; + break; + } +#endif + const auto _ePathType = RtlDetermineDosPathNameType_U(_szNewDirectory); + if (_ePathType == RtlPathTypeUnknown || _ePathType == RtlPathTypeDriveRelative || _ePathType == RtlPathTypeRelative) + { + _lStatus = ERROR_INVALID_PARAMETER; + break; + } + + const auto _cchNewDirectory = internal::StringLength(_szNewDirectory); + const auto _cbNewDirectory = _cchNewDirectory * sizeof(wchar_t); + auto _pEntry = (Fallback::DllDirectoryListEntry*)internal::Alloc(sizeof(Fallback::DllDirectoryListEntry) + _cbNewDirectory + sizeof(wchar_t)); + if (!_pEntry) + { + _lStatus = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + _pEntry->cchPath = _cchNewDirectory; + memcpy(_pEntry->szPath, _szNewDirectory, _cbNewDirectory); + _pEntry->szPath[_cchNewDirectory] = L'\0'; + + ::AcquireSRWLockExclusive(&Fallback::s_DllDirectoryListLock); + Fallback::s_DllDirectoryList.PushBack(_pEntry); + ::ReleaseSRWLockExclusive(&Fallback::s_DllDirectoryListLock); + + return _pEntry; + } while (false); + + SetLastError(_lStatus); + return nullptr; + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT6_2) + + // 最低受支持的客户端 Windows 8 [仅限桌面应用],在 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008 上KB2533623 + // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + RemoveDllDirectory, + _In_ DLL_DIRECTORY_COOKIE _pCookie + ) + { + if (const auto _pfnRemoveDllDirectory = try_get_RemoveDllDirectory()) + { + return _pfnRemoveDllDirectory(_pCookie); + } + + ::AcquireSRWLockExclusive(&Fallback::s_DllDirectoryListLock); + const auto _bSuccess = Fallback::s_DllDirectoryList.Remove((Fallback::DllDirectoryListEntry*)_pCookie); + ::ReleaseSRWLockExclusive(&Fallback::s_DllDirectoryListLock); + + if (!_bSuccess) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + internal::Free(_pCookie); + return TRUE; + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + + // Minimum supported client Windows Vista, Windows XP with SP1 [desktop apps only] + // Minimum supported server Windows Server 2003[desktop apps only] + __DEFINE_THUNK( + kernel32, + 8, + DWORD, + WINAPI, + GetDllDirectoryW, + _In_ DWORD _cchBufferLength, + _Out_writes_to_opt_(_cchBufferLength, return + 1) LPWSTR _szBuffer + ) + { + if (const auto _pfnGetDllDirectoryW = try_get_GetDllDirectoryW()) + { + return _pfnGetDllDirectoryW(_cchBufferLength, _szBuffer); + } + + if (_szBuffer && _cchBufferLength) + { + _szBuffer[0] = L'\0'; + } + + LSTATUS _lStatus = ERROR_SUCCESS; + DWORD _uResult = 0; + + const auto _cbBufferLength = _cchBufferLength * sizeof(wchar_t); + ::AcquireSRWLockShared(&Fallback::s_DllDirectoryLock); + const auto _cbResult = Fallback::s_sDllDirectory.Length + sizeof(wchar_t); + if (_szBuffer && _cbResult <= _cbBufferLength) + { + memcpy(_szBuffer, Fallback::s_sDllDirectory.Buffer, Fallback::s_sDllDirectory.Length); + _uResult = Fallback::s_sDllDirectory.Length / sizeof(wchar_t); + _szBuffer[_uResult] = L'\0'; + } + else + { + _uResult = _cbResult / sizeof(wchar_t); + } + ::ReleaseSRWLockShared(&Fallback::s_DllDirectoryLock); + + SetLastError(_lStatus); + return _uResult; + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + + // Minimum supported client Windows Vista, Windows XP with SP1 [desktop apps only] + // Minimum supported server Windows Server 2003[desktop apps only] + __DEFINE_THUNK( + kernel32, + 8, + DWORD, + WINAPI, + GetDllDirectoryA, + _In_ DWORD _cchBufferLength, + _Out_writes_to_opt_(_cchBufferLength, return + 1) LPSTR _szBuffer + ) + { + if (const auto _pfnGetDllDirectoryA = try_get_GetDllDirectoryA()) + { + return _pfnGetDllDirectoryA(_cchBufferLength, _szBuffer); + } + + if (_szBuffer && _cchBufferLength) + { + _szBuffer[0] = '\0'; + } + + LSTATUS _lStatus = ERROR_SUCCESS; + DWORD _uResult = 0; + + const UINT _uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + ::AcquireSRWLockShared(&Fallback::s_DllDirectoryLock); + if (const auto _cchLength = Fallback::s_sDllDirectory.Length / sizeof(wchar_t)) + { + int _nResult; + do + { + if (_szBuffer && _cchBufferLength > 1) + { + _nResult = WideCharToMultiByte(_uCodePage, 0, Fallback::s_sDllDirectory.Buffer, _cchLength, _szBuffer, _cchBufferLength - 1, nullptr, nullptr); + if (_nResult > 0) + { + _uResult = _nResult; + _szBuffer[_uResult] = '\0'; + break; + } + + _szBuffer[0] = '\0'; + _lStatus = GetLastError(); + if (_lStatus != ERROR_INSUFFICIENT_BUFFER) + { + break; + } + } + + _nResult = WideCharToMultiByte(_uCodePage, 0, Fallback::s_sDllDirectory.Buffer, _cchLength, 0, 0, nullptr, nullptr); + if (_nResult <= 0) + { + _lStatus = GetLastError(); + break; + } + + // 缓冲区额外加个 '0' + _uResult = _nResult + 1; + } while (false); + } + ::ReleaseSRWLockShared(&Fallback::s_DllDirectoryLock); + + SetLastError(_lStatus); + return _uResult; + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + + // Minimum supported client Windows Vista, Windows XP with SP1 [desktop apps only] + // Minimum supported server Windows Server 2003[desktop apps only] + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + SetDllDirectoryW, + _In_opt_ LPCWSTR _szPathName + ) + { + if (const auto _pfnSetDllDirectoryW = try_get_SetDllDirectoryW()) + { + return _pfnSetDllDirectoryW(_szPathName); + } + + return Fallback::DownlevelSetDllDirectoryW(_szPathName); + } +#endif + + +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + + // Minimum supported client Windows Vista, Windows XP with SP1 [desktop apps only] + // Minimum supported server Windows Server 2003[desktop apps only] + __DEFINE_THUNK( + kernel32, + 4, + BOOL, + WINAPI, + SetDllDirectoryA, + _In_opt_ LPCSTR _szPathName + ) + { + if (const auto _pfnSetDllDirectoryA = try_get_SetDllDirectoryA()) + { + return _pfnSetDllDirectoryA(_szPathName); + } + + wchar_t _szPathNameUnicode[512] = {}; + if (!_szPathName) + { + return Fallback::DownlevelSetDllDirectoryW(nullptr); + } + + UNICODE_STRING _sPathName = { 0, sizeof(_szPathNameUnicode), _szPathNameUnicode }; + auto _lStatus = internal::Basep8BitStringToStaticUnicodeString(&_sPathName, _szPathName); + if (_lStatus != ERROR_SUCCESS) + { + SetLastError(_lStatus); + return FALSE; + } + + return Fallback::DownlevelSetDllDirectoryW(_szPathNameUnicode); + } +#endif +} diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj index 97f56ea..6d1893b 100644 --- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj +++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj @@ -185,6 +185,7 @@ + @@ -225,6 +226,7 @@ + @@ -328,4 +330,4 @@ - + \ No newline at end of file diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters index 9fff719..9b098ee 100644 --- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters +++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters @@ -96,6 +96,9 @@ 源文件\UnitTest + + 源文件\UnitTest + @@ -374,6 +377,9 @@ Shared + + Shared + @@ -392,4 +398,4 @@ 源文件\def\x64 - + \ No newline at end of file diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-libraryloader.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-libraryloader.UnitTest.cpp new file mode 100644 index 0000000..3433c34 --- /dev/null +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-libraryloader.UnitTest.cpp @@ -0,0 +1,190 @@ +#include "pch.h" +#include "Thunks/api-ms-win-core-libraryloader.hpp" + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace api_ms_win_core_libraryloader +{ +#if (YY_Thunks_Target < __WindowsNT5_1_SP1) + TEST_CLASS(SetDllDirectoryW_A) + { + AwaysNullGuard Guard; + + public: + SetDllDirectoryW_A() + { + Guard |= YY::Thunks::aways_null_try_get_SetDllDirectoryW; + Guard |= YY::Thunks::aways_null_try_get_GetDllDirectoryW; + Guard |= YY::Thunks::aways_null_try_get_SetDllDirectoryA; + Guard |= YY::Thunks::aways_null_try_get_GetDllDirectoryA; + } + + TEST_METHOD(常规) + { + { + wchar_t _szBuffer[MAX_PATH]; + static LPCWSTR s_szPathList[] = + { + L"C:\\123", + L"C:\\456", + L"C:\\789", + nullptr, + }; + + for (auto _szPath : s_szPathList) + { + Assert::IsTrue(::SetDllDirectoryW(_szPath)); + + const auto _uResult = ::GetDllDirectoryW(_countof(_szBuffer), _szBuffer); + if (_szPath) + { + Assert::AreEqual(size_t(_uResult), wcslen(_szPath)); + Assert::AreEqual(_szBuffer, _szPath); + } + else + { + Assert::AreEqual(_uResult, 0ul); + } + } + } + + { + char _szBuffer[MAX_PATH]; + static LPCSTR s_szPathList[] = + { + "C:\\123", + "C:\\456", + "C:\\789", + nullptr, + }; + + for (auto _szPath : s_szPathList) + { + Assert::IsTrue(::SetDllDirectoryA(_szPath)); + + const auto _uResult = ::GetDllDirectoryA(_countof(_szBuffer), _szBuffer); + if (_szPath) + { + Assert::AreEqual(size_t(_uResult), strlen(_szPath)); + Assert::AreEqual(_szBuffer, _szPath); + } + else + { + Assert::AreEqual(_uResult, 0ul); + } + } + } + } + + TEST_METHOD(W_A互调验证) + { + { + Assert::IsTrue(::SetDllDirectoryA("C:\\123")); + wchar_t _szBuffer[MAX_PATH]; + const auto _uResult = ::GetDllDirectoryW(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), strlen("C:\\123")); + Assert::AreEqual(_szBuffer, L"C:\\123"); + } + + { + Assert::IsTrue(::SetDllDirectoryW(L"C:\\456")); + char _szBuffer[MAX_PATH]; + const auto _uResult = ::GetDllDirectoryA(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), strlen("C:\\456")); + Assert::AreEqual(_szBuffer, "C:\\456"); + } + + Assert::IsTrue(::SetDllDirectoryW(nullptr)); + } + }; + + TEST_CLASS(GetDllDirectoryW_A) + { + AwaysNullGuard Guard; + + public: + GetDllDirectoryW_A() + { + Guard |= YY::Thunks::aways_null_try_get_SetDllDirectoryW; + Guard |= YY::Thunks::aways_null_try_get_GetDllDirectoryW; + Guard |= YY::Thunks::aways_null_try_get_SetDllDirectoryA; + Guard |= YY::Thunks::aways_null_try_get_GetDllDirectoryA; + } + + TEST_METHOD(常规) + { + { + Assert::IsTrue(::SetDllDirectoryA("C:\\123")); + char _szBuffer[MAX_PATH]; + const auto _uResult = ::GetDllDirectoryA(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), strlen("C:\\123")); + Assert::AreEqual(_szBuffer, "C:\\123"); + } + + { + Assert::IsTrue(::SetDllDirectoryW(L"C:\\456")); + wchar_t _szBuffer[MAX_PATH]; + const auto _uResult = ::GetDllDirectoryW(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), strlen("C:\\456")); + Assert::AreEqual(_szBuffer, L"C:\\456"); + } + + Assert::IsTrue(::SetDllDirectoryW(nullptr)); + } + + TEST_METHOD(缓冲区不足验证) + { + Assert::IsTrue(::SetDllDirectoryW(L"C:\\456")); + + { + wchar_t _szBuffer[6]; + const auto _uResult = ::GetDllDirectoryW(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), _countof(L"C:\\456")); + Assert::AreEqual(_szBuffer, L""); + } + + { + wchar_t _szBuffer[7]; + const auto _uResult = ::GetDllDirectoryW(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), wcslen(L"C:\\456")); + Assert::AreEqual(_szBuffer, L"C:\\456"); + } + + { + char _szBuffer[6]; + const auto _uResult = ::GetDllDirectoryA(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), _countof("C:\\456")); + Assert::AreEqual(_szBuffer, ""); + } + + { + char _szBuffer[7]; + const auto _uResult = ::GetDllDirectoryA(_countof(_szBuffer), _szBuffer); + Assert::AreEqual(size_t(_uResult), strlen("C:\\456")); + Assert::AreEqual(_szBuffer, "C:\\456"); + } + + Assert::IsTrue(::SetDllDirectoryW(nullptr)); + } + }; +#endif + + TEST_CLASS(AddDllDirectory_RemoveDllDirectory) + { + AwaysNullGuard Guard; + + public: + AddDllDirectory_RemoveDllDirectory() + { + Guard |= YY::Thunks::aways_null_try_get_AddDllDirectory; + Guard |= YY::Thunks::aways_null_try_get_RemoveDllDirectory; + } + + TEST_METHOD(常规) + { + auto _pCookie = AddDllDirectory(L"C:\\123"); + Assert::IsNotNull(_pCookie); + Assert::IsTrue(RemoveDllDirectory(_pCookie)); + } + }; +}